Skip to content

Measure request latency to the last byte (read the full response body) - #227

Merged
fcsonline merged 1 commit into
fcsonline:masterfrom
zoosky:force-read-response-body
Jun 1, 2026
Merged

fcsonline merged 1 commit into
fcsonline:masterfrom
zoosky:force-read-response-body

Conversation

@zoosky

@zoosky zoosky commented May 31, 2026

Copy link
Copy Markdown
Contributor

Problem

drill stops its timer as soon as the response headers arrive (client.execute().await), but reqwest streams the body lazily. The body is only read when a request uses assign — and even then after the timer has already stopped. So any endpoint serving a non-trivial body (files, large JSON) is reported as completing far faster than it really does. This is the accuracy issue reported in #74, and the same root cause as #182.

Fix

Read the entire response body before stopping the timer, so latency now measures time-to-last-byte — matching wrk, k6, and vegeta. Status, headers and cookies are snapshotted into an owned ResponseData before the body stream is consumed, so the assign path and verbose logging keep working unchanged. The assign body is decoded with the response Content-Type charset via encoding_rs (exactly what reqwest's text() did internally), so non-UTF-8 bodies aren't corrupted by reading the body ourselves. encoding_rs is already a transitive dependency through reqwest, so this adds no new crates to the tree.

Test

Adds measures_full_body_transfer_time: a bare HTTP server sends the response head immediately, then delays 300 ms before the body; the measured duration must be ≥ 250 ms. This fails against the old header-only timing and passes now. Also adds unit tests for the charset parsing/decoding. cargo fmt --check, cargo clippy --all-targets -- -D warnings, and cargo test are all green.

Note on approach

#74 asked for an option to force-read the body. I've made accurate measurement the default instead (no flag), since a load tester reporting time-to-headers is misleading and every mainstream tool measures to last byte. The trade-off is that reported latencies for body-heavy endpoints will increase — they become correct. One follow-on behavior worth flagging: a body that doesn't finish transferring within --timeout is now reported as a connection error (status 520) rather than its HTTP status, because the body read is part of the timed request.

If you'd prefer to preserve existing numbers by default and gate this behind a --read-body/--force-body flag, I'm happy to adjust — your call as maintainer.

Fixes #74.

@zoosky
zoosky force-pushed the force-read-response-body branch from 64db7ed to ad49543 Compare May 31, 2026 16:05
@fcsonline

fcsonline commented May 31, 2026

Copy link
Copy Markdown
Owner

Awesome! Can you solve the merge conflict?

drill stopped its timer as soon as the response headers arrived
(`client.execute().await`), but reqwest streams the body lazily, so
body-transfer time was never measured. The body was only read when a
request used `assign`, and even then after the timer had already stopped.
Endpoints serving non-trivial bodies (files, large JSON) were reported as
completing far faster than they really did.

Read the full response body before stopping the timer, so latency now
measures time-to-last-byte, matching wrk, k6 and vegeta. Status, headers
and cookies are snapshotted into an owned struct before the body stream is
consumed.

The body is drained one chunk at a time and only buffered when a request
uses `assign` (then decoded with the response Content-Type charset, via
encoding_rs, as reqwest's `text()` did); otherwise each chunk is dropped as
it arrives, so peak memory stays O(chunk) rather than O(body) for large
responses. Timing and keep-alive are unchanged -- the body is still read to
the last byte.

Adds regression tests: a server that delays its body (latency must include
the delay) and a 1 MiB non-assign body (drained but not retained).

Fixes fcsonline#74.
@zoosky
zoosky force-pushed the force-read-response-body branch from ad49543 to ad91f14 Compare June 1, 2026 08:08
@zoosky

zoosky commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Done. Please verify.

@fcsonline
fcsonline merged commit cd22905 into fcsonline:master Jun 1, 2026
4 checks passed
@zoosky
zoosky deleted the force-read-response-body branch June 2, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add option to force drill to read response body

2 participants