fix(server): correctly handle CONNECT requests
- In the higher-level `Server` API, since connection upgrades aren't yet supported, returning a 2xx response to a `CONNECT` request is a user error. A 500 response is written to the client, the connection is closed, and an error is reported back to the user. - In the lower-level `server::Connection` API, where upgrades *are* supported, a 2xx response correctly marks the response as the final one, instead of trying to parse more requests afterwards.
This commit is contained in:
@@ -1147,6 +1147,70 @@ fn upgrades() {
|
||||
assert_eq!(vec, b"bar=foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn http_connect() {
|
||||
use tokio_io::io::{read_to_end, write_all};
|
||||
let _ = pretty_env_logger::try_init();
|
||||
let runtime = Runtime::new().unwrap();
|
||||
let listener = tcp_bind(&"127.0.0.1:0".parse().unwrap(), &runtime.reactor()).unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut tcp = connect(&addr);
|
||||
tcp.write_all(b"\
|
||||
CONNECT localhost:80 HTTP/1.1\r\n\
|
||||
\r\n\
|
||||
eagerly optimistic\
|
||||
").expect("write 1");
|
||||
let mut buf = [0; 256];
|
||||
tcp.read(&mut buf).expect("read 1");
|
||||
|
||||
let expected = "HTTP/1.1 200 OK\r\n";
|
||||
assert_eq!(s(&buf[..expected.len()]), expected);
|
||||
let _ = tx.send(());
|
||||
|
||||
let n = tcp.read(&mut buf).expect("read 2");
|
||||
assert_eq!(s(&buf[..n]), "foo=bar");
|
||||
tcp.write_all(b"bar=foo").expect("write 2");
|
||||
});
|
||||
|
||||
let fut = listener.incoming()
|
||||
.into_future()
|
||||
.map_err(|_| -> hyper::Error { unreachable!() })
|
||||
.and_then(|(item, _incoming)| {
|
||||
let socket = item.unwrap();
|
||||
let conn = Http::new()
|
||||
.serve_connection(socket, service_fn(|_| {
|
||||
let res = Response::builder()
|
||||
.status(200)
|
||||
.body(hyper::Body::empty())
|
||||
.unwrap();
|
||||
Ok::<_, hyper::Error>(res)
|
||||
}));
|
||||
|
||||
let mut conn_opt = Some(conn);
|
||||
future::poll_fn(move || {
|
||||
try_ready!(conn_opt.as_mut().unwrap().poll_without_shutdown());
|
||||
// conn is done with HTTP now
|
||||
Ok(conn_opt.take().unwrap().into())
|
||||
})
|
||||
});
|
||||
|
||||
let conn = fut.wait().unwrap();
|
||||
|
||||
// wait so that we don't write until other side saw 101 response
|
||||
rx.wait().unwrap();
|
||||
|
||||
let parts = conn.into_parts();
|
||||
let io = parts.io;
|
||||
assert_eq!(parts.read_buf, "eagerly optimistic");
|
||||
|
||||
let io = write_all(io, b"foo=bar").wait().unwrap().0;
|
||||
let vec = read_to_end(io, vec![]).wait().unwrap().1;
|
||||
assert_eq!(vec, b"bar=foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_errors_send_4xx_response() {
|
||||
let runtime = Runtime::new().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user