fix(http1): only send 100 Continue if request body is polled
Before, if a client request included an `Expect: 100-continue` header, the `100 Continue` response was sent immediately. However, this is problematic if the service is going to reply with some 4xx status code and reject the body. This change delays the automatic sending of the `100 Continue` status until the service has call `poll_data` on the request body once.
This commit is contained in:
@@ -785,6 +785,57 @@ fn expect_continue_but_no_body_is_ignored() {
|
||||
assert_eq!(&resp[..expected.len()], expected);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn expect_continue_waits_for_body_poll() {
|
||||
let _ = pretty_env_logger::try_init();
|
||||
let mut listener = tcp_bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
|
||||
let child = thread::spawn(move || {
|
||||
let mut tcp = connect(&addr);
|
||||
|
||||
tcp.write_all(
|
||||
b"\
|
||||
POST /foo HTTP/1.1\r\n\
|
||||
Host: example.domain\r\n\
|
||||
Expect: 100-continue\r\n\
|
||||
Content-Length: 100\r\n\
|
||||
Connection: Close\r\n\
|
||||
\r\n\
|
||||
",
|
||||
)
|
||||
.expect("write");
|
||||
|
||||
let expected = "HTTP/1.1 400 Bad Request\r\n";
|
||||
let mut resp = String::new();
|
||||
tcp.read_to_string(&mut resp).expect("read");
|
||||
|
||||
assert_eq!(&resp[..expected.len()], expected);
|
||||
});
|
||||
|
||||
let (socket, _) = listener.accept().await.expect("accept");
|
||||
|
||||
Http::new()
|
||||
.serve_connection(
|
||||
socket,
|
||||
service_fn(|req| {
|
||||
assert_eq!(req.headers()["expect"], "100-continue");
|
||||
// But! We're never going to poll the body!
|
||||
tokio::time::delay_for(Duration::from_millis(50)).map(move |_| {
|
||||
// Move and drop the req, so we don't auto-close
|
||||
drop(req);
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(hyper::Body::empty())
|
||||
})
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.expect("serve_connection");
|
||||
|
||||
child.join().expect("client thread");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pipeline_disabled() {
|
||||
let server = serve();
|
||||
|
||||
Reference in New Issue
Block a user