From 7a676822c292e3f405fc21ac0897393d715a12ea Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Sat, 8 Oct 2022 17:00:06 +0200 Subject: [PATCH] x/net/http2: gzipReader will reset zr to nil after closing body The existing implementation does not reset gz.zr. After Close, gzipReader closes underlying response body but buffered data can still be read. gzipReader on Close sets the gz.zerr to fs.ErrClosed so next Read after Close will return it immediately. Fixes golang/go#56020 Change-Id: I8a31e4c65656b9abc3023855b8e04342e1e77cbb Reviewed-on: https://go-review.googlesource.com/c/net/+/440555 Reviewed-by: Damien Neil Run-TryBot: Damien Neil TryBot-Result: Gopher Robot Reviewed-by: Than McIntosh --- http2/transport.go | 7 ++++++- http2/transport_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/http2/transport.go b/http2/transport.go index e78804b22..5a179b669 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -16,6 +16,7 @@ import ( "errors" "fmt" "io" + "io/fs" "log" "math" mathrand "math/rand" @@ -2985,7 +2986,11 @@ func (gz *gzipReader) Read(p []byte) (n int, err error) { } func (gz *gzipReader) Close() error { - return gz.body.Close() + if err := gz.body.Close(); err != nil { + return err + } + gz.zerr = fs.ErrClosed + return nil } type errorReader struct{ err error } diff --git a/http2/transport_test.go b/http2/transport_test.go index 67afb57c3..c7389119f 100644 --- a/http2/transport_test.go +++ b/http2/transport_test.go @@ -7,6 +7,7 @@ package http2 import ( "bufio" "bytes" + "compress/gzip" "context" "crypto/tls" "encoding/hex" @@ -14,6 +15,7 @@ import ( "flag" "fmt" "io" + "io/fs" "io/ioutil" "log" "math/rand" @@ -2503,6 +2505,28 @@ func TestGzipReader_DoubleReadCrash(t *testing.T) { } } +func TestGzipReader_ReadAfterClose(t *testing.T) { + body := bytes.Buffer{} + w := gzip.NewWriter(&body) + w.Write([]byte("012345679")) + w.Close() + gz := &gzipReader{ + body: ioutil.NopCloser(&body), + } + var buf [1]byte + n, err := gz.Read(buf[:]) + if n != 1 || err != nil { + t.Fatalf("first Read = %v, %v; want 1, nil", n, err) + } + if err := gz.Close(); err != nil { + t.Fatalf("gz Close error: %v", err) + } + n, err = gz.Read(buf[:]) + if n != 0 || err != fs.ErrClosed { + t.Fatalf("Read after close = %v, %v; want 0, fs.ErrClosed", n, err) + } +} + func TestTransportNewTLSConfig(t *testing.T) { tests := [...]struct { conf *tls.Config