From: Maxime Henrion Date: Wed, 8 Jul 2026 16:37:07 +0000 (-0400) Subject: BUG/MINOR: shctx: fix shctx_row_data_get() when offset exceeds a block X-Git-Url: http://git.kaiwu.me/http/static/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=6750c36adfc82bb4102a2c7a12b1caa20801c39f;p=haproxy.git BUG/MINOR: shctx: fix shctx_row_data_get() when offset exceeds a block The loop advanced the block pointer only after the copy, but skipped blocks preceding with a continue, which bypassed that advance. As a result any read starting past the first block copied nothing. This notably affects conditional requests: should_send_notmodified_response() reads the stored ETag at entry->etag_offset, so a cached response whose ETag header sits beyond the first block fails revalidation and is served in full (200) instead of 304. Rewrite the loop as a for() so the block pointer always advances, regardless of whether the current block is copied or skipped. This should be backported as far as 2.6. --- diff --git a/src/shctx.c b/src/shctx.c index fb1611396..cb580b14e 100644 --- a/src/shctx.c +++ b/src/shctx.c @@ -226,30 +226,22 @@ int shctx_row_data_append(struct shared_context *shctx, struct shared_block *fir int shctx_row_data_get(struct shared_context *shctx, struct shared_block *first, unsigned char *dst, int offset, int len) { - int count = 0, size = 0, start = -1; + int count, size, start = -1; struct shared_block *block; /* can't copy more */ if (len > first->len) len = first->len; - block = first; - count = 0; - /* Pass through the blocks to copy them */ - do { - if (count >= first->block_count || len <= 0) - break; - - count++; - /* continue until we are in right block - corresponding to the offset */ - if (count < offset / shctx->block_size + 1) + /* Walk the blocks, skipping those that precede the one holding . */ + for (block = first, count = 0; count < first->block_count && len > 0; + block = LIST_ELEM(block->list.n, struct shared_block *, list), count++) { + if (count < offset / shctx->block_size) continue; - /* on the first block, data won't possibly began at offset 0 */ + /* the first copied block may not start at its beginning */ if (start == -1) - start = offset - (count - 1) * shctx->block_size; - + start = offset - count * shctx->block_size; BUG_ON(start < 0); /* size can be lower than a block when copying the last block */ @@ -260,9 +252,7 @@ int shctx_row_data_get(struct shared_context *shctx, struct shared_block *first, dst += size; len -= size; start = 0; - - block = LIST_ELEM(block->list.n, struct shared_block*, list); - } while (block != first); + } return len; }