]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: fix requests failing on short gzip body
authorAlexey Borzenkov <snaury@gmail.com>
Thu, 10 Apr 2014 21:12:36 +0000 (14:12 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 10 Apr 2014 21:12:36 +0000 (14:12 -0700)
Fixes #7750.

LGTM=bradfitz
R=golang-codereviews, ibilicc, bradfitz
CC=golang-codereviews
https://golang.org/cl/84850043

src/pkg/net/http/transport.go
src/pkg/net/http/transport_test.go

index de0ff9ce57ca4347d15c630f571ecab2225b2dd5..1d776c26806195a0429116e48433a4e0366553a8 100644 (file)
@@ -812,13 +812,7 @@ func (pc *persistConn) readLoop() {
                                resp.Header.Del("Content-Encoding")
                                resp.Header.Del("Content-Length")
                                resp.ContentLength = -1
-                               gzReader, zerr := gzip.NewReader(resp.Body)
-                               if zerr != nil {
-                                       pc.close()
-                                       err = zerr
-                               } else {
-                                       resp.Body = &readerAndCloser{gzReader, resp.Body}
-                               }
+                               resp.Body = &gzipReader{body: resp.Body}
                        }
                        resp.Body = &bodyEOFSignal{body: resp.Body}
                }
@@ -1156,6 +1150,27 @@ func (es *bodyEOFSignal) condfn(err error) {
        es.fn = nil
 }
 
+// gzipReader wraps a response body so it can lazily
+// call gzip.NewReader on the first call to Read
+type gzipReader struct {
+       body io.ReadCloser // underlying Response.Body
+       zr   io.Reader     // lazily-initialized gzip reader
+}
+
+func (gz *gzipReader) Read(p []byte) (n int, err error) {
+       if gz.zr == nil {
+               gz.zr, err = gzip.NewReader(gz.body)
+               if err != nil {
+                       return 0, err
+               }
+       }
+       return gz.zr.Read(p)
+}
+
+func (gz *gzipReader) Close() error {
+       return gz.body.Close()
+}
+
 type readerAndCloser struct {
        io.Reader
        io.Closer
index 24466e53690ba9cef75a8b1fbae6282a9f929736..6c9711931201e1072afbf9b8557234efbac62545 100644 (file)
@@ -803,6 +803,33 @@ func TestTransportGzipRecursive(t *testing.T) {
        }
 }
 
+// golang.org/issue/7750: request fails when server replies with
+// a short gzip body
+func TestTransportGzipShort(t *testing.T) {
+       defer afterTest(t)
+       ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+               w.Header().Set("Content-Encoding", "gzip")
+               w.Write([]byte{0x1f, 0x8b})
+       }))
+       defer ts.Close()
+
+       tr := &Transport{}
+       defer tr.CloseIdleConnections()
+       c := &Client{Transport: tr}
+       res, err := c.Get(ts.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer res.Body.Close()
+       _, err = ioutil.ReadAll(res.Body)
+       if err == nil {
+               t.Fatal("Expect an error from reading a body.")
+       }
+       if err != io.ErrUnexpectedEOF {
+               t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err)
+       }
+}
+
 // tests that persistent goroutine connections shut down when no longer desired.
 func TestTransportPersistConnLeak(t *testing.T) {
        if runtime.GOOS == "plan9" {