fix(lib): properly handle body streaming errors

This commit is contained in:
Sean McArthur
2018-01-11 13:58:16 -08:00
parent 7888451408
commit 7a48d0e8b4
4 changed files with 143 additions and 77 deletions

View File

@@ -14,7 +14,7 @@ use tokio_core::net::TcpListener;
use tokio_core::reactor::{Core, Timeout};
use tokio_io::{AsyncRead, AsyncWrite};
use std::net::{TcpStream, SocketAddr};
use std::net::{TcpStream, Shutdown, SocketAddr};
use std::io::{self, Read, Write};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc;
@@ -223,6 +223,26 @@ fn post_with_chunked_body() {
assert_eq!(server.body(), b"qwert");
}
#[test]
fn post_with_incomplete_body() {
extern crate pretty_env_logger;
let _ = pretty_env_logger::try_init();
let server = serve();
let mut req = connect(server.addr());
req.write_all(b"\
POST / HTTP/1.1\r\n\
Host: example.domain\r\n\
Content-Length: 10\r\n\
\r\n\
12345\
").expect("write");
req.shutdown(Shutdown::Write).expect("shutdown write");
server.body_err();
req.read(&mut [0; 256]).expect("read");
}
#[test]
fn empty_response_chunked() {
let server = serve();
@@ -746,24 +766,34 @@ impl Serve {
}
pub fn remote_addr(&self) -> SocketAddr {
match self.msg_rx.try_recv() {
match self.msg_rx.recv() {
Ok(Msg::Addr(addr)) => addr,
other => panic!("expected remote addr, found: {:?}", other),
}
}
fn body(&self) -> Vec<u8> {
self.try_body().expect("body")
}
fn body_err(&self) -> hyper::Error {
self.try_body().expect_err("body_err")
}
fn try_body(&self) -> Result<Vec<u8>, hyper::Error> {
let mut buf = vec![];
loop {
match self.msg_rx.try_recv() {
match self.msg_rx.recv() {
Ok(Msg::Chunk(msg)) => {
buf.extend(&msg);
},
Ok(Msg::Addr(_)) => {},
Err(_) => break,
Ok(Msg::Error(e)) => return Err(e),
Ok(Msg::End) => break,
Err(e) => panic!("expected body, found: {:?}", e),
}
}
buf
Ok(buf)
}
fn reply(&self) -> ReplyBuilder {
@@ -821,6 +851,8 @@ enum Msg {
//Head(Request),
Addr(SocketAddr),
Chunk(Vec<u8>),
Error(hyper::Error),
End,
}
impl NewService for TestService {
@@ -841,15 +873,23 @@ impl Service for TestService {
type Error = hyper::Error;
type Future = Box<Future<Item=Response, Error=hyper::Error>>;
fn call(&self, req: Request) -> Self::Future {
let tx = self.tx.clone();
let tx1 = self.tx.clone();
let tx2 = self.tx.clone();
#[allow(deprecated)]
let remote_addr = req.remote_addr().expect("remote_addr");
tx.lock().unwrap().send(Msg::Addr(remote_addr)).unwrap();
tx1.lock().unwrap().send(Msg::Addr(remote_addr)).unwrap();
let replies = self.reply.clone();
Box::new(req.body().for_each(move |chunk| {
tx.lock().unwrap().send(Msg::Chunk(chunk.to_vec())).unwrap();
tx1.lock().unwrap().send(Msg::Chunk(chunk.to_vec())).unwrap();
Ok(())
}).then(move |result| {
let msg = match result {
Ok(()) => Msg::End,
Err(e) => Msg::Error(e),
};
tx2.lock().unwrap().send(msg).unwrap();
Ok(())
}).map(move |_| {
let mut res = Response::new();