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 <dneil@google.com>
Run-TryBot: Damien Neil <dneil@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/http2/transport.go b/http2/transport.go
index e78804b..5a179b6 100644
--- a/http2/transport.go
+++ b/http2/transport.go
@@ -16,6 +16,7 @@
 	"errors"
 	"fmt"
 	"io"
+	"io/fs"
 	"log"
 	"math"
 	mathrand "math/rand"
@@ -2985,7 +2986,11 @@
 }
 
 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 67afb57..c738911 100644
--- a/http2/transport_test.go
+++ b/http2/transport_test.go
@@ -7,6 +7,7 @@
 import (
 	"bufio"
 	"bytes"
+	"compress/gzip"
 	"context"
 	"crypto/tls"
 	"encoding/hex"
@@ -14,6 +15,7 @@
 	"flag"
 	"fmt"
 	"io"
+	"io/fs"
 	"io/ioutil"
 	"log"
 	"math/rand"
@@ -2503,6 +2505,28 @@
 	}
 }
 
+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