From 8d7faf53127583f97f483a891222f0ddd1281616 Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Mon, 7 Sep 2026 21:51:38 +0200 Subject: [PATCH] httpd: retransmit a continued chunk from where it was sent A file larger than the output buffer is sent in two phases: the first buffer goes out in MSS-sized pieces, with o_idx walking through it, and what is left is then streamed from flash a chunk at a time into outbuf from offset 0. The continuation branch never reset o_idx, so it kept the offset the first phase had left it at, while uip_rexmit() retransmits from outbuf + o_idx. A lost continuation segment was therefore retransmitted as the bytes 1460 further into the buffer, which the client accepts as the missing data, and with o_idx + slen past the 2500-byte buffer it also read whatever xdata follows outbuf. Reproduced on a SWTGW218AS by dropping 15% of the switch's TCP segments: seven of eight fetches of a 21 kB static came back the right length and the wrong content, each first differing at a fixed phase of the 1460-byte chunk. With o_idx reset the retransmission repeats the chunk it sent. The o_idx += slen right after slen = 0 went too: it added nothing. (cherry picked from commit 789d29423288f89411a41673e26ce1854b296c3d) --- httpd/httpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index bb4061b1..55d1e174 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -865,7 +865,6 @@ void httpd_appcall(void) o_idx += uip_mss(); } else { slen = 0; - o_idx += slen; } s->tstate = TSTATE_ACKED; @@ -886,7 +885,8 @@ void httpd_appcall(void) flash_region.addr = cont_addr; flash_region.len = slen; flash_read_bulk(outbuf); - uip_send(outbuf, slen); + o_idx = 0; + uip_send(outbuf + o_idx, slen); cont_len -= slen; cont_addr += slen; s->tstate = TSTATE_TX;