HttpClientLight: time out reading a body when the server goes silent (#25139)

writeToStreamDataBlock() looped for as long as connected() held, waiting
for the rest of the body with no time limit. A server that stops sending
part way through a body without closing the connection - a computer that
sleeps, a cable pulled, a network that drops between the two ends - leaves
connected() true for ever, so the read never returned. Called from the main
loop, as Berry's webclient get_string() is, it left the device answering
nothing, not even its web page, until it was power-cycled.

Give up after _tcpTimeout without data, returning HTTPC_ERROR_READ_TIMEOUT,
as handleHeaderResponse() already does for the headers. A body that keeps
arriving, however slowly, is unaffected: each piece resets the clock.
This commit is contained in:
Adam Matthews authored and GitHub committed 2026-10-14 15:12:37 +02:00
1 parent 1bb26b29c4
commit c95c241fa3
1 file changed
+10
@@ -1370,6 +1370,10 @@ int HTTPClientLight::writeToStreamDataBlock(Stream * stream, int size)
uint8_t * buff = (uint8_t *) malloc(buff_size);
if(buff) {
// a server gone silent without closing stays connected(): give up
// after _tcpTimeout without data, as handleHeaderResponse() does
unsigned long lastDataTime = millis();
// read all data from server
while(connected() && (len > 0 || len == -1)) {
@@ -1442,8 +1446,14 @@ int HTTPClientLight::writeToStreamDataBlock(Stream * stream, int size)
len -= readBytes;
}
lastDataTime = millis();
delay(0);
} else {
if((millis() - lastDataTime) > _tcpTimeout) {
log_w("read timeout after %d bytes", bytesWritten);
free(buff);
return HTTPC_ERROR_READ_TIMEOUT;
}
delay(1);
}
}