Two problems in the fixed-length request-body reader (src/http/request.rs, BodyType::Fixed), both affecting POST uploads (e.g. /backend/empty). Both reproduce on current master (1.4.0).
1. Upload hangs when Content-Length is not a multiple of 1024
The body is read in fixed 1024-byte chunks with read_exact:
let mut buffer = [0; 1024];
let mut len: usize = 0;
loop {
let bytes_read = buf_reader.read_exact(&mut buffer).await;
match bytes_read {
Ok(_) => { len += buffer.len(); if len >= body_size as usize { break; } }
Err(_) => break,
// ...
}
}
read_exact only returns once the full 1024-byte buffer is filled. When Content-Length % 1024 != 0, the final partial chunk never fills, so — against a client that keeps the connection open (no half-close) — read_exact blocks indefinitely waiting for bytes that never arrive, and the upload hangs until the client times out. (len += buffer.len() also counts a full 1024 regardless of the bytes actually read, so it can over-read into a following pipelined request.)
Repro: send a POST to /backend/empty with Content-Length: 50000000 (50000000 % 1024 == 128), send exactly that many bytes, and keep the socket open. The server never responds. Padding the body to a 1024 multiple (e.g. 50000896) works — which is the workaround clients use today.
2. Expect: 100-continue is never answered
The request headers are parsed, but Expect is never inspected, so a client that sends Expect: 100-continue waits out its continue-timeout (~1s for curl) before sending the body — on every upload.
Repro: curl -X POST --data-binary @<50MB file> http://<server>/backend/empty (curl adds Expect: 100-continue for bodies > 1 KB) takes ~1s longer than the same request with -H "Expect:".
I have a fix with regression tests ready and will open a PR.
Two problems in the fixed-length request-body reader (
src/http/request.rs,BodyType::Fixed), both affectingPOSTuploads (e.g./backend/empty). Both reproduce on currentmaster(1.4.0).1. Upload hangs when
Content-Lengthis not a multiple of 1024The body is read in fixed 1024-byte chunks with
read_exact:read_exactonly returns once the full 1024-byte buffer is filled. WhenContent-Length % 1024 != 0, the final partial chunk never fills, so — against a client that keeps the connection open (no half-close) —read_exactblocks indefinitely waiting for bytes that never arrive, and the upload hangs until the client times out. (len += buffer.len()also counts a full 1024 regardless of the bytes actually read, so it can over-read into a following pipelined request.)Repro: send a
POSTto/backend/emptywithContent-Length: 50000000(50000000 % 1024 == 128), send exactly that many bytes, and keep the socket open. The server never responds. Padding the body to a 1024 multiple (e.g.50000896) works — which is the workaround clients use today.2.
Expect: 100-continueis never answeredThe request headers are parsed, but
Expectis never inspected, so a client that sendsExpect: 100-continuewaits out its continue-timeout (~1s for curl) before sending the body — on every upload.Repro:
curl -X POST --data-binary @<50MB file> http://<server>/backend/empty(curl addsExpect: 100-continuefor bodies > 1 KB) takes ~1s longer than the same request with-H "Expect:".I have a fix with regression tests ready and will open a PR.