mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-11 05:27:47 +00:00
fix(pools): return pooled gzip reader on Reset error
GetGzipReader got a reader from the pool, Reset it, and on error returned a fresh gzip.NewReader while never returning the pooled reader to the pool — one leaked reader per reset error (non-gzip input), silently draining the pool. Return the pooled reader without Close (Close panics because the decompressor is nil until a header parses); the next caller's Reset reinitialises it. Test: TestGetGzipReader_ResetErrorPath (error path leaves the pool usable for subsequent valid gzip reads).
This commit is contained in:
+6
-1
@@ -78,7 +78,12 @@ func PutGzipWriter(gz *gzip.Writer) {
|
||||
func GetGzipReader(r io.Reader) (*gzip.Reader, error) {
|
||||
gr := gzipReaderPool.Get().(*gzip.Reader)
|
||||
if err := gr.Reset(r); err != nil {
|
||||
// If reset fails, create a new reader
|
||||
// Reset failed (e.g. non-gzip data): return the pooled reader so it
|
||||
// isn't leaked, and hand back a fresh one for this call. We must not
|
||||
// call gr.Close() here — the decompressor is nil until a header
|
||||
// parses, so Close would panic. The next GetGzipReader's Reset
|
||||
// reinitialises it.
|
||||
gzipReaderPool.Put(gr)
|
||||
return gzip.NewReader(r)
|
||||
}
|
||||
return gr, nil
|
||||
|
||||
@@ -415,3 +415,31 @@ func BenchmarkWithoutPool(b *testing.B) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestGetGzipReader_ResetErrorPath exercises the path where the pooled reader
|
||||
// fails to Reset (non-gzip input). The pooled reader must be returned to the
|
||||
// pool and a usable reader handed back; a subsequent valid gzip read must
|
||||
// still succeed so the pool is not left in a broken state.
|
||||
func (suite *BufferPoolTestSuite) TestGetGzipReader_ResetErrorPath() {
|
||||
t := suite.T()
|
||||
// Non-gzip input -> Reset fails -> fresh reader returned (with error).
|
||||
gr1, err := GetGzipReader(strings.NewReader("not gzip data at all"))
|
||||
assert.Error(t, err, "expected error decoding non-gzip data")
|
||||
if gr1 != nil {
|
||||
PutGzipReader(gr1)
|
||||
}
|
||||
|
||||
// Valid gzip input afterwards must still work, proving the pool is usable.
|
||||
var buf bytes.Buffer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
_, werr := zw.Write([]byte("hello world"))
|
||||
assert.NoError(t, werr)
|
||||
assert.NoError(t, zw.Close())
|
||||
|
||||
gr2, err := GetGzipReader(bytes.NewReader(buf.Bytes()))
|
||||
assert.NoError(t, err)
|
||||
defer PutGzipReader(gr2)
|
||||
decoded, rerr := io.ReadAll(gr2)
|
||||
assert.NoError(t, rerr)
|
||||
assert.Equal(t, "hello world", string(decoded))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user