feat(client): implement connection pooling for Client

Closes #830
Closes #848
This commit is contained in:
Sean McArthur
2016-07-08 10:07:02 -07:00
parent 67436c5bf6
commit 2904668105
6 changed files with 268 additions and 74 deletions

View File

@@ -72,7 +72,7 @@ impl Drop for Serve {
struct TestHandler {
tx: mpsc::Sender<Msg>,
rx: mpsc::Receiver<Reply>,
reply: Vec<Reply>,
peeked: Option<Vec<u8>>,
timeout: Option<Duration>,
}
@@ -123,28 +123,26 @@ impl Handler<HttpStream> for TestHandler {
}
fn on_response(&mut self, res: &mut Response) -> Next {
loop {
match self.rx.try_recv() {
Ok(Reply::Status(s)) => {
for reply in self.reply.drain(..) {
match reply {
Reply::Status(s) => {
res.set_status(s);
},
Ok(Reply::Headers(headers)) => {
Reply::Headers(headers) => {
use std::iter::Extend;
res.headers_mut().extend(headers.iter());
},
Ok(Reply::Body(body)) => {
Reply::Body(body) => {
self.peeked = Some(body);
},
Err(..) => {
return if self.peeked.is_some() {
self.next(Next::write())
} else {
self.next(Next::end())
};
},
}
}
if self.peeked.is_some() {
self.next(Next::write())
} else {
self.next(Next::end())
}
}
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
@@ -167,13 +165,18 @@ fn serve_with_timeout(dur: Option<Duration>) -> Serve {
let (msg_tx, msg_rx) = mpsc::channel();
let (reply_tx, reply_rx) = mpsc::channel();
let mut reply_rx = Some(reply_rx);
let (listening, server) = Server::http(&"127.0.0.1:0".parse().unwrap()).unwrap()
.handle(move |_| TestHandler {
tx: msg_tx.clone(),
timeout: dur,
rx: reply_rx.take().unwrap(),
peeked: None,
.handle(move |_| {
let mut replies = Vec::new();
while let Ok(reply) = reply_rx.try_recv() {
replies.push(reply);
}
TestHandler {
tx: msg_tx.clone(),
timeout: dur,
reply: replies,
peeked: None,
}
}).unwrap();
@@ -377,3 +380,62 @@ fn server_empty_response_chunked_without_calling_write() {
assert_eq!(lines.next(), Some(""));
assert_eq!(lines.next(), None);
}
#[test]
fn server_keep_alive() {
extern crate env_logger;
env_logger::init().unwrap();
let foo_bar = b"foo bar baz";
let server = serve();
server.reply()
.status(hyper::Ok)
.header(hyper::header::ContentLength(foo_bar.len() as u64))
.body(foo_bar);
let mut req = TcpStream::connect(server.addr()).unwrap();
req.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
req.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
req.write_all(b"\
GET / HTTP/1.1\r\n\
Host: example.domain\r\n\
Connection: keep-alive\r\n\
\r\n\
").expect("writing 1");
let mut buf = [0; 1024 * 8];
loop {
let n = req.read(&mut buf[..]).expect("reading 1");
if n < buf.len() {
if &buf[n - foo_bar.len()..n] == foo_bar {
break;
} else {
println!("{:?}", ::std::str::from_utf8(&buf[..n]));
}
}
}
// try again!
let quux = b"zar quux";
server.reply()
.status(hyper::Ok)
.header(hyper::header::ContentLength(quux.len() as u64))
.body(quux);
req.write_all(b"\
GET /quux HTTP/1.1\r\n\
Host: example.domain\r\n\
Connection: close\r\n\
\r\n\
").expect("writing 2");
let mut buf = [0; 1024 * 8];
loop {
let n = req.read(&mut buf[..]).expect("reading 2");
assert!(n > 0, "n = {}", n);
if n < buf.len() {
if &buf[n - quux.len()..n] == quux {
break;
}
}
}
}