test(h1): re-enable h1 decoder tests
This commit is contained in:
@@ -637,12 +637,6 @@ where I: AsyncRead + AsyncWrite + Unpin,
|
||||
trace!("{}: prepare possible HTTP upgrade", T::LOG);
|
||||
self.state.prepare_upgrade()
|
||||
}
|
||||
|
||||
// Used in h1::dispatch tests
|
||||
#[cfg(test)]
|
||||
pub(super) fn io_mut(&mut self) -> &mut I {
|
||||
self.io.io_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, B: Buf, T> fmt::Debug for Conn<I, B, T> {
|
||||
|
||||
@@ -143,6 +143,13 @@ impl Decoder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
async fn decode_fut<R: MemRead>(&mut self, body: &mut R) -> Result<Bytes, io::Error> {
|
||||
futures_util::future::poll_fn(move |cx| {
|
||||
self.decode(cx, body)
|
||||
}).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -319,65 +326,58 @@ impl StdError for IncompleteBody {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// FIXME: re-implement tests with `async/await`, this import should
|
||||
// trigger a warning to remind us
|
||||
use crate::Error;
|
||||
/*
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use super::Decoder;
|
||||
use super::ChunkedState;
|
||||
use super::super::io::MemRead;
|
||||
use futures::{Async, Poll};
|
||||
use bytes::{BytesMut, Bytes};
|
||||
use crate::mock::AsyncIo;
|
||||
use std::time::Duration;
|
||||
use std::pin::Pin;
|
||||
use tokio_io::AsyncRead;
|
||||
use super::*;
|
||||
|
||||
impl<'a> MemRead for &'a [u8] {
|
||||
fn read_mem(&mut self, len: usize) -> Poll<Result<Bytes, io::Error>> {
|
||||
fn read_mem(&mut self, _: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {
|
||||
let n = ::std::cmp::min(len, self.len());
|
||||
if n > 0 {
|
||||
let (a, b) = self.split_at(n);
|
||||
let mut buf = BytesMut::from(a);
|
||||
let buf = Bytes::from(a);
|
||||
*self = b;
|
||||
Poll::Ready(Ok(buf.split_to(n).freeze()))
|
||||
Poll::Ready(Ok(buf))
|
||||
} else {
|
||||
Poll::Ready(Ok(Bytes::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait HelpUnwrap<T> {
|
||||
fn unwrap(self) -> T;
|
||||
}
|
||||
impl HelpUnwrap<Bytes> for Async<Bytes> {
|
||||
fn unwrap(self) -> Bytes {
|
||||
match self {
|
||||
Async::Ready(bytes) => bytes,
|
||||
Async::NotReady => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl HelpUnwrap<ChunkedState> for Async<ChunkedState> {
|
||||
fn unwrap(self) -> ChunkedState {
|
||||
match self {
|
||||
Async::Ready(state) => state,
|
||||
Async::NotReady => panic!(),
|
||||
}
|
||||
impl<'a> MemRead for &'a mut (dyn AsyncRead + Unpin) {
|
||||
fn read_mem(&mut self, cx: &mut task::Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {
|
||||
let mut v = vec![0; len];
|
||||
let n = ready!(Pin::new(self).poll_read(cx, &mut v)?);
|
||||
Poll::Ready(Ok(Bytes::from(&v[..n])))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunk_size() {
|
||||
/*
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use super::Decoder;
|
||||
use super::ChunkedState;
|
||||
use futures::{Async, Poll};
|
||||
use bytes::{BytesMut, Bytes};
|
||||
use crate::mock::AsyncIo;
|
||||
*/
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_read_chunk_size() {
|
||||
use std::io::ErrorKind::{UnexpectedEof, InvalidInput};
|
||||
|
||||
fn read(s: &str) -> u64 {
|
||||
async fn read(s: &str) -> u64 {
|
||||
let mut state = ChunkedState::Size;
|
||||
let rdr = &mut s.as_bytes();
|
||||
let mut size = 0;
|
||||
loop {
|
||||
let result = state.step(rdr, &mut size, &mut None);
|
||||
let result = futures_util::future::poll_fn(|cx| {
|
||||
state.step(cx, rdr, &mut size, &mut None)
|
||||
}).await;
|
||||
let desc = format!("read_size failed for {:?}", s);
|
||||
state = result.expect(desc.as_str()).unwrap();
|
||||
state = result.expect(desc.as_str());
|
||||
if state == ChunkedState::Body || state == ChunkedState::EndCr {
|
||||
break;
|
||||
}
|
||||
@@ -385,14 +385,16 @@ mod tests {
|
||||
size
|
||||
}
|
||||
|
||||
fn read_err(s: &str, expected_err: io::ErrorKind) {
|
||||
async fn read_err(s: &str, expected_err: io::ErrorKind) {
|
||||
let mut state = ChunkedState::Size;
|
||||
let rdr = &mut s.as_bytes();
|
||||
let mut size = 0;
|
||||
loop {
|
||||
let result = state.step(rdr, &mut size, &mut None);
|
||||
let result = futures_util::future::poll_fn(|cx| {
|
||||
state.step(cx, rdr, &mut size, &mut None)
|
||||
}).await;
|
||||
state = match result {
|
||||
Ok(s) => s.unwrap(),
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
assert!(expected_err == e.kind(), "Reading {:?}, expected {:?}, but got {:?}",
|
||||
s, expected_err, e.kind());
|
||||
@@ -405,139 +407,150 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(1, read("1\r\n"));
|
||||
assert_eq!(1, read("01\r\n"));
|
||||
assert_eq!(0, read("0\r\n"));
|
||||
assert_eq!(0, read("00\r\n"));
|
||||
assert_eq!(10, read("A\r\n"));
|
||||
assert_eq!(10, read("a\r\n"));
|
||||
assert_eq!(255, read("Ff\r\n"));
|
||||
assert_eq!(255, read("Ff \r\n"));
|
||||
assert_eq!(1, read("1\r\n").await);
|
||||
assert_eq!(1, read("01\r\n").await);
|
||||
assert_eq!(0, read("0\r\n").await);
|
||||
assert_eq!(0, read("00\r\n").await);
|
||||
assert_eq!(10, read("A\r\n").await);
|
||||
assert_eq!(10, read("a\r\n").await);
|
||||
assert_eq!(255, read("Ff\r\n").await);
|
||||
assert_eq!(255, read("Ff \r\n").await);
|
||||
// Missing LF or CRLF
|
||||
read_err("F\rF", InvalidInput);
|
||||
read_err("F", UnexpectedEof);
|
||||
read_err("F\rF", InvalidInput).await;
|
||||
read_err("F", UnexpectedEof).await;
|
||||
// Invalid hex digit
|
||||
read_err("X\r\n", InvalidInput);
|
||||
read_err("1X\r\n", InvalidInput);
|
||||
read_err("-\r\n", InvalidInput);
|
||||
read_err("-1\r\n", InvalidInput);
|
||||
read_err("X\r\n", InvalidInput).await;
|
||||
read_err("1X\r\n", InvalidInput).await;
|
||||
read_err("-\r\n", InvalidInput).await;
|
||||
read_err("-1\r\n", InvalidInput).await;
|
||||
// Acceptable (if not fully valid) extensions do not influence the size
|
||||
assert_eq!(1, read("1;extension\r\n"));
|
||||
assert_eq!(10, read("a;ext name=value\r\n"));
|
||||
assert_eq!(1, read("1;extension;extension2\r\n"));
|
||||
assert_eq!(1, read("1;;; ;\r\n"));
|
||||
assert_eq!(2, read("2; extension...\r\n"));
|
||||
assert_eq!(3, read("3 ; extension=123\r\n"));
|
||||
assert_eq!(3, read("3 ;\r\n"));
|
||||
assert_eq!(3, read("3 ; \r\n"));
|
||||
assert_eq!(1, read("1;extension\r\n").await);
|
||||
assert_eq!(10, read("a;ext name=value\r\n").await);
|
||||
assert_eq!(1, read("1;extension;extension2\r\n").await);
|
||||
assert_eq!(1, read("1;;; ;\r\n").await);
|
||||
assert_eq!(2, read("2; extension...\r\n").await);
|
||||
assert_eq!(3, read("3 ; extension=123\r\n").await);
|
||||
assert_eq!(3, read("3 ;\r\n").await);
|
||||
assert_eq!(3, read("3 ; \r\n").await);
|
||||
// Invalid extensions cause an error
|
||||
read_err("1 invalid extension\r\n", InvalidInput);
|
||||
read_err("1 A\r\n", InvalidInput);
|
||||
read_err("1;no CRLF", UnexpectedEof);
|
||||
read_err("1 invalid extension\r\n", InvalidInput).await;
|
||||
read_err("1 A\r\n", InvalidInput).await;
|
||||
read_err("1;no CRLF", UnexpectedEof).await;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_sized_early_eof() {
|
||||
#[tokio::test]
|
||||
async fn test_read_sized_early_eof() {
|
||||
let mut bytes = &b"foo bar"[..];
|
||||
let mut decoder = Decoder::length(10);
|
||||
assert_eq!(decoder.decode(&mut bytes).unwrap().unwrap().len(), 7);
|
||||
let e = decoder.decode(&mut bytes).unwrap_err();
|
||||
assert_eq!(decoder.decode_fut(&mut bytes).await.unwrap().len(), 7);
|
||||
let e = decoder.decode_fut(&mut bytes).await.unwrap_err();
|
||||
assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunked_early_eof() {
|
||||
#[tokio::test]
|
||||
async fn test_read_chunked_early_eof() {
|
||||
let mut bytes = &b"\
|
||||
9\r\n\
|
||||
foo bar\
|
||||
"[..];
|
||||
let mut decoder = Decoder::chunked();
|
||||
assert_eq!(decoder.decode(&mut bytes).unwrap().unwrap().len(), 7);
|
||||
let e = decoder.decode(&mut bytes).unwrap_err();
|
||||
assert_eq!(decoder.decode_fut(&mut bytes).await.unwrap().len(), 7);
|
||||
let e = decoder.decode_fut(&mut bytes).await.unwrap_err();
|
||||
assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunked_single_read() {
|
||||
#[tokio::test]
|
||||
async fn test_read_chunked_single_read() {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..];
|
||||
let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode").unwrap();
|
||||
let buf = Decoder::chunked().decode_fut(&mut mock_buf).await.expect("decode");
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunked_after_eof() {
|
||||
#[tokio::test]
|
||||
async fn test_read_chunked_after_eof() {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n\r\n"[..];
|
||||
let mut decoder = Decoder::chunked();
|
||||
|
||||
// normal read
|
||||
let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap();
|
||||
let buf = decoder.decode_fut(&mut mock_buf).await.unwrap();
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
|
||||
// eof read
|
||||
let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap();
|
||||
let buf = decoder.decode_fut(&mut mock_buf).await.expect("decode");
|
||||
assert_eq!(0, buf.len());
|
||||
|
||||
// ensure read after eof also returns eof
|
||||
let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap();
|
||||
let buf = decoder.decode_fut(&mut mock_buf).await.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,
|
||||
async fn read_async(mut decoder: Decoder,
|
||||
content: &[u8],
|
||||
block_at: usize)
|
||||
-> String {
|
||||
let content_len = content.len();
|
||||
let mut ins = AsyncIo::new(content, block_at);
|
||||
let mut outs = Vec::new();
|
||||
|
||||
let mut ins = if block_at == 0 {
|
||||
tokio_test::io::Builder::new()
|
||||
.wait(Duration::from_millis(10))
|
||||
.read(content)
|
||||
.build()
|
||||
} else {
|
||||
tokio_test::io::Builder::new()
|
||||
.read(&content[..block_at])
|
||||
.wait(Duration::from_millis(10))
|
||||
.read(&content[block_at..])
|
||||
.build()
|
||||
};
|
||||
|
||||
let mut ins = &mut ins as &mut (dyn AsyncRead + Unpin);
|
||||
|
||||
loop {
|
||||
match decoder.decode(&mut ins).expect("unexpected decode error: {}") {
|
||||
Async::Ready(buf) => {
|
||||
if buf.is_empty() {
|
||||
break; // eof
|
||||
}
|
||||
outs.write(buf.as_ref()).expect("write buffer");
|
||||
},
|
||||
Async::NotReady => {
|
||||
ins.block_in(content_len); // we only block once
|
||||
}
|
||||
};
|
||||
let buf = decoder
|
||||
.decode_fut(&mut ins)
|
||||
.await
|
||||
.expect("unexpected decode error");
|
||||
if buf.is_empty() {
|
||||
break; // eof
|
||||
}
|
||||
outs.extend(buf.as_ref());
|
||||
}
|
||||
|
||||
String::from_utf8(outs).expect("decode String")
|
||||
}
|
||||
|
||||
// iterate over the different ways that this async read could go.
|
||||
// tests blocking a read at each byte along the content - The shotgun approach
|
||||
fn all_async_cases(content: &str, expected: &str, decoder: Decoder) {
|
||||
async fn all_async_cases(content: &str, expected: &str, decoder: Decoder) {
|
||||
let content_len = content.len();
|
||||
for block_at in 0..content_len {
|
||||
let actual = read_async(decoder.clone(), content.as_bytes(), block_at);
|
||||
let actual = read_async(decoder.clone(), content.as_bytes(), block_at).await;
|
||||
assert_eq!(expected, &actual) //, "Failed async. Blocking at {}", block_at);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_length_async() {
|
||||
#[tokio::test]
|
||||
async fn test_read_length_async() {
|
||||
let content = "foobar";
|
||||
all_async_cases(content, content, Decoder::length(content.len() as u64));
|
||||
all_async_cases(content, content, Decoder::length(content.len() as u64)).await;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_chunked_async() {
|
||||
#[tokio::test]
|
||||
async fn test_read_chunked_async() {
|
||||
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());
|
||||
all_async_cases(content, expected, Decoder::chunked()).await;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_eof_async() {
|
||||
#[tokio::test]
|
||||
async fn test_read_eof_async() {
|
||||
let content = "foobar";
|
||||
all_async_cases(content, content, Decoder::eof());
|
||||
all_async_cases(content, content, Decoder::eof()).await;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user