feat(client): add method to end a chunked body for a Request
Closes #831
This commit is contained in:
129
tests/client.rs
129
tests/client.rs
@@ -8,6 +8,7 @@ use std::time::Duration;
|
||||
|
||||
use hyper::client::{Handler, Request, Response, HttpConnector};
|
||||
use hyper::{Method, StatusCode, Next, Encoder, Decoder};
|
||||
use hyper::header::Headers;
|
||||
use hyper::net::HttpStream;
|
||||
|
||||
fn s(bytes: &[u8]) -> &str {
|
||||
@@ -48,10 +49,24 @@ fn read(opts: &Opts) -> Next {
|
||||
impl Handler<HttpStream> for TestHandler {
|
||||
fn on_request(&mut self, req: &mut Request) -> Next {
|
||||
req.set_method(self.opts.method.clone());
|
||||
read(&self.opts)
|
||||
req.headers_mut().extend(self.opts.headers.iter());
|
||||
if self.opts.body.is_some() {
|
||||
Next::write()
|
||||
} else {
|
||||
read(&self.opts)
|
||||
}
|
||||
}
|
||||
|
||||
fn on_request_writable(&mut self, _encoder: &mut Encoder<HttpStream>) -> Next {
|
||||
fn on_request_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
||||
if let Some(ref mut body) = self.opts.body {
|
||||
let n = encoder.write(body).unwrap();
|
||||
*body = &body[n..];
|
||||
|
||||
if !body.is_empty() {
|
||||
return Next::write()
|
||||
}
|
||||
}
|
||||
encoder.close();
|
||||
read(&self.opts)
|
||||
}
|
||||
|
||||
@@ -103,14 +118,18 @@ struct Client {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Opts {
|
||||
body: Option<&'static [u8]>,
|
||||
method: Method,
|
||||
headers: Headers,
|
||||
read_timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
impl Default for Opts {
|
||||
fn default() -> Opts {
|
||||
Opts {
|
||||
body: None,
|
||||
method: Method::Get,
|
||||
headers: Headers::new(),
|
||||
read_timeout: None,
|
||||
}
|
||||
}
|
||||
@@ -126,6 +145,16 @@ impl Opts {
|
||||
self
|
||||
}
|
||||
|
||||
fn header<H: ::hyper::header::Header>(mut self, header: H) -> Opts {
|
||||
self.headers.set(header);
|
||||
self
|
||||
}
|
||||
|
||||
fn body(mut self, body: Option<&'static [u8]>) -> Opts {
|
||||
self.body = body;
|
||||
self
|
||||
}
|
||||
|
||||
fn read_timeout(mut self, timeout: Duration) -> Opts {
|
||||
self.read_timeout = Some(timeout);
|
||||
self
|
||||
@@ -167,33 +196,46 @@ macro_rules! test {
|
||||
request:
|
||||
method: $client_method:ident,
|
||||
url: $client_url:expr,
|
||||
headers: [ $($request_headers:expr,)* ],
|
||||
body: $request_body:expr,
|
||||
|
||||
response:
|
||||
status: $client_status:ident,
|
||||
headers: [ $($client_headers:expr,)* ],
|
||||
body: $client_body:expr
|
||||
headers: [ $($response_headers:expr,)* ],
|
||||
body: $response_body:expr,
|
||||
) => (
|
||||
#[test]
|
||||
fn $name() {
|
||||
#[allow(unused)]
|
||||
use hyper::header::*;
|
||||
let server = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = server.local_addr().unwrap();
|
||||
let client = client();
|
||||
let res = client.request(format!($client_url, addr=addr), opts().method(Method::$client_method));
|
||||
let opts = opts()
|
||||
.method(Method::$client_method)
|
||||
.body($request_body);
|
||||
$(
|
||||
let opts = opts.header($request_headers);
|
||||
)*
|
||||
let res = client.request(format!($client_url, addr=addr), opts);
|
||||
|
||||
let mut inc = server.accept().unwrap().0;
|
||||
inc.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
|
||||
inc.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
|
||||
let mut buf = [0; 4096];
|
||||
let n = inc.read(&mut buf).unwrap();
|
||||
let expected = format!($server_expected, addr=addr);
|
||||
let mut buf = [0; 4096];
|
||||
let mut n = 0;
|
||||
while n < buf.len() && n < expected.len() {
|
||||
n += inc.read(&mut buf[n..]).unwrap();
|
||||
}
|
||||
assert_eq!(s(&buf[..n]), expected);
|
||||
|
||||
inc.write_all($server_reply.as_ref()).unwrap();
|
||||
|
||||
if let Msg::Head(head) = res.recv().unwrap() {
|
||||
use hyper::header::*;
|
||||
assert_eq!(head.status(), &StatusCode::$client_status);
|
||||
$(
|
||||
assert_eq!(head.headers().get(), Some(&$client_headers));
|
||||
assert_eq!(head.headers().get(), Some(&$response_headers));
|
||||
)*
|
||||
} else {
|
||||
panic!("we lost the head!");
|
||||
@@ -205,23 +247,27 @@ macro_rules! test {
|
||||
);
|
||||
}
|
||||
|
||||
static REPLY_OK: &'static str = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";
|
||||
|
||||
test! {
|
||||
name: client_get,
|
||||
|
||||
server:
|
||||
expected: "GET / HTTP/1.1\r\nHost: {addr}\r\n\r\n",
|
||||
reply: "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
|
||||
reply: REPLY_OK,
|
||||
|
||||
client:
|
||||
request:
|
||||
method: Get,
|
||||
url: "http://{addr}/",
|
||||
headers: [],
|
||||
body: None,
|
||||
response:
|
||||
status: Ok,
|
||||
headers: [
|
||||
ContentLength(0),
|
||||
],
|
||||
body: None
|
||||
body: None,
|
||||
}
|
||||
|
||||
test! {
|
||||
@@ -229,19 +275,76 @@ test! {
|
||||
|
||||
server:
|
||||
expected: "GET /foo?key=val HTTP/1.1\r\nHost: {addr}\r\n\r\n",
|
||||
reply: "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
|
||||
reply: REPLY_OK,
|
||||
|
||||
client:
|
||||
request:
|
||||
method: Get,
|
||||
url: "http://{addr}/foo?key=val#dont_send_me",
|
||||
headers: [],
|
||||
body: None,
|
||||
response:
|
||||
status: Ok,
|
||||
headers: [
|
||||
ContentLength(0),
|
||||
],
|
||||
body: None
|
||||
body: None,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: client_post_sized,
|
||||
|
||||
server:
|
||||
expected: "\
|
||||
POST /length HTTP/1.1\r\n\
|
||||
Host: {addr}\r\n\
|
||||
Content-Length: 7\r\n\
|
||||
\r\n\
|
||||
foo bar\
|
||||
",
|
||||
reply: REPLY_OK,
|
||||
|
||||
client:
|
||||
request:
|
||||
method: Post,
|
||||
url: "http://{addr}/length",
|
||||
headers: [
|
||||
ContentLength(7),
|
||||
],
|
||||
body: Some(b"foo bar"),
|
||||
response:
|
||||
status: Ok,
|
||||
headers: [],
|
||||
body: None,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: client_post_chunked,
|
||||
|
||||
server:
|
||||
expected: "\
|
||||
POST /chunks HTTP/1.1\r\n\
|
||||
Host: {addr}\r\n\
|
||||
Transfer-Encoding: chunked\r\n\
|
||||
\r\n\
|
||||
B\r\n\
|
||||
foo bar baz\r\n\
|
||||
0\r\n\r\n\
|
||||
",
|
||||
reply: REPLY_OK,
|
||||
|
||||
client:
|
||||
request:
|
||||
method: Post,
|
||||
url: "http://{addr}/chunks",
|
||||
headers: [
|
||||
TransferEncoding::chunked(),
|
||||
],
|
||||
body: Some(b"foo bar baz"),
|
||||
response:
|
||||
status: Ok,
|
||||
headers: [],
|
||||
body: None,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user