On Wed, Oct 28, 2026 at 11:19:59AM +0100, Adam Szymanski wrote: > SPOP_CF_DEM_BLOCK_ANY is documented as "aggregate of the demux flags above > except DALLOC/DFULL", like H2_CF_DEM_BLOCK_ANY and FCGI_CF_DEM_BLOCK_ANY, but > its value 0x7E0 also covers SPOP_CF_DEM_DALLOC (0x20) and SPOP_CF_DEM_DFULL > (0x40). > > When a single recv() fills the demux buffer, spop_recv() sets > SPOP_CF_DEM_DFULL. spop_process() then skips spop_process_demux() because > the flag is part of SPOP_CF_DEM_BLOCK_ANY, and the only place clearing > SPOP_CF_DEM_DFULL is inside that skipped block. spop_recv_allowed() also > refuses to read. The connection stays stuck with a full dbuf forever: the > peer sees a zero TCP window, ACK frames are never parsed, every stream > attached to the connection times out, and new streams keep being attached > to it because it is still considered available. > > This happens with pipelining when enough ACK frames are queued at once to > fill the 16kB demux buffer in one read (e.g. ACKs carrying ~1-3kB > variables), so "no option pipelining" in the spoe-agent section hides it. > > The value must be 0x780 (MROOM|SALLOC|SFULL|TOOMANY). > > Reproduced on HAProxy 3.4.7 with nbthread 4, pipelining enabled, > 50 concurrent HTTP keep-alive clients, and a Go SPOA agent returning > ACK frames carrying approximately 3kB of variables. In three 10-second > test runs, the unpatched version left 3-5 connections stuck with > DEM_DFULL and produced 400-520 SPOE timeouts per run. With the fix, > no stuck connections or SPOE timeouts were observed. > > This must be backported as far as 3.1. > > Co-authored-by: ITGG <[email protected]>
Indeed, good catch. Now applied, thank you! Willy

