A response delivering occasional bytes can remain within each read inactivity limit while taking far too long overall. A read timeout need not measure the entire transfer duration.

Set the policy according to the workload. A finite archive needs a completion budget; an event stream may legitimately continue for hours and spend time quiet.

Measure useful progress

For a file download, retain an overall deadline and consider the client's supported low-speed or progress controls. Define the interval and amount of useful data. A heartbeat byte may show activity without making meaningful progress toward the file's completion.

Keep tunnel setup separate from body transfer. Waiting for CONNECT to complete and receiving a slow destination body are different stages with different evidence.

Consume or close the response on every exit path. Leaving a slow stream open can make the next request wait for pool capacity, producing another timeout for a different reason.

If observed duration exceeds the intended policy, inspect the exact client version and read loop. A correctly functioning inactivity timer, custom-loop behavior, and an implementation bug need different fixes.

Related articles