Skip to content

fix(middleware): gzip Write must return len(b), not the buffer length#2981

Open
ultramcu wants to merge 1 commit into
labstack:v4from
ultramcu:fix/gzip-write-count
Open

fix(middleware): gzip Write must return len(b), not the buffer length#2981
ultramcu wants to merge 1 commit into
labstack:v4from
ultramcu:fix/gzip-write-count

Conversation

@ultramcu
Copy link
Copy Markdown

Issue

middleware.gzipResponseWriter.Write violates the io.Writer contract. When a buffered write crosses MinLength, it flushes the whole buffer and returns the buffer length:

return w.Writer.Write(w.buffer.Bytes())

Because the buffer also holds bytes from earlier (sub-MinLength) writes, the returned n can exceed len(b). The io.Writer contract requires 0 <= n <= len(b), and consumers that validate this panic.

In particular io.Copy — which echo.Context#Stream uses internally (io.Copy(c.Response(), r)) — panics with:

bytes.Reader.WriteTo: invalid Write count

So streaming a response through the Gzip middleware crashes the request whenever a small write was buffered before the threshold-crossing write.

Fix

Flush the buffer as before, but report only len(b) (the bytes accepted from this call):

if _, err := w.Writer.Write(w.buffer.Bytes()); err != nil {
    return 0, err
}
return n, nil

n is already len(b) from the preceding w.buffer.Write(b).

Tests

Added middleware/compress_writecount_test.go:

  • TestGzipWriteReturnsCorrectCountWrite reports len(b), never the buffered total.
  • TestGzipIoCopyDoesNotPanic — streaming through gzip with io.Copy no longer panics.

Both fail on master (the second panics with invalid Write count) and pass with the fix. Existing compress tests (incl. TestGzipWithMinLengthChunked) and the full suite stay green under go test -race ./....

@aldas
Copy link
Copy Markdown
Contributor

aldas commented May 24, 2026

please rebase your PR

gzipResponseWriter.Write returned the total buffered byte count (any
previously buffered chunks plus the current slice) once a write crossed
MinLength, so it could return n > len(b). That violates the io.Writer
contract and makes standard-library consumers that validate the count
panic -- notably io.Copy (used by Context.Stream), which panics with
"bytes.Reader.WriteTo: invalid Write count".

Flush the buffer as before but report only len(b) as written.
@ultramcu ultramcu force-pushed the fix/gzip-write-count branch from 8d83429 to 630e123 Compare May 24, 2026 20:07
@ultramcu ultramcu changed the base branch from master to v4 May 24, 2026 20:07
@ultramcu
Copy link
Copy Markdown
Author

Thanks @aldas — done. I retargeted the PR to the v4 branch and rebased: the branch now sits directly on top of the current v4 tip (25685e6), a single commit, and GitHub shows it mergeable/clean. (The original mismatch was that it was opened against master, which is now the v5 module — the fix and test target v4.) Ready for review when you have a moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants