Skip to content

Commit 130be07

Browse files
committed
fix gzip not sending response code for no content responses (404, 301/302 redirects etc)
1 parent 60af056 commit 130be07

File tree

2 files changed

+38
-20
lines changed

2 files changed

+38
-20
lines changed

middleware/compress.go

+6
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,16 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
107107

108108
grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw, minLength: config.MinLength, buffer: buf}
109109
defer func() {
110+
// There are different reasons for cases when we have not yet written response to the client and now need to do so.
111+
// a) handler response had only response code and no response body (ala 404 or redirects etc). Response code need to be written now.
112+
// b) body is shorter than our minimum length threshold and being buffered currently and needs to be written
110113
if !grw.wroteBody {
111114
if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
112115
res.Header().Del(echo.HeaderContentEncoding)
113116
}
117+
if grw.wroteHeader {
118+
rw.WriteHeader(grw.code)
119+
}
114120
// We have to reset response to it's pristine state when
115121
// nothing is written to body or error is returned.
116122
// See issue #424, #407.

middleware/compress_test.go

+32-20
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,6 @@ func TestGzip(t *testing.T) {
8989
}
9090

9191
func TestGzipWithMinLength(t *testing.T) {
92-
assert := assert.New(t)
93-
9492
e := echo.New()
9593
// Minimal response length
9694
e.Use(GzipWithConfig(GzipConfig{MinLength: 10}))
@@ -103,19 +101,17 @@ func TestGzipWithMinLength(t *testing.T) {
103101
req.Header.Set(echo.HeaderAcceptEncoding, gzipScheme)
104102
rec := httptest.NewRecorder()
105103
e.ServeHTTP(rec, req)
106-
assert.Equal(gzipScheme, rec.Header().Get(echo.HeaderContentEncoding))
104+
assert.Equal(t, gzipScheme, rec.Header().Get(echo.HeaderContentEncoding))
107105
r, err := gzip.NewReader(rec.Body)
108-
if assert.NoError(err) {
106+
if assert.NoError(t, err) {
109107
buf := new(bytes.Buffer)
110108
defer r.Close()
111109
buf.ReadFrom(r)
112-
assert.Equal("foobarfoobar", buf.String())
110+
assert.Equal(t, "foobarfoobar", buf.String())
113111
}
114112
}
115113

116114
func TestGzipWithMinLengthTooShort(t *testing.T) {
117-
assert := assert.New(t)
118-
119115
e := echo.New()
120116
// Minimal response length
121117
e.Use(GzipWithConfig(GzipConfig{MinLength: 10}))
@@ -127,13 +123,29 @@ func TestGzipWithMinLengthTooShort(t *testing.T) {
127123
req.Header.Set(echo.HeaderAcceptEncoding, gzipScheme)
128124
rec := httptest.NewRecorder()
129125
e.ServeHTTP(rec, req)
130-
assert.Equal("", rec.Header().Get(echo.HeaderContentEncoding))
131-
assert.Contains(rec.Body.String(), "test")
126+
assert.Equal(t, "", rec.Header().Get(echo.HeaderContentEncoding))
127+
assert.Contains(t, rec.Body.String(), "test")
132128
}
133129

134-
func TestGzipWithMinLengthChunked(t *testing.T) {
135-
assert := assert.New(t)
130+
func TestGzipWithResponseWithoutBody(t *testing.T) {
131+
e := echo.New()
132+
133+
e.Use(Gzip())
134+
e.GET("/", func(c echo.Context) error {
135+
return c.Redirect(http.StatusMovedPermanently, "http://localhost")
136+
})
137+
138+
req := httptest.NewRequest(http.MethodGet, "/", nil)
139+
req.Header.Set(echo.HeaderAcceptEncoding, gzipScheme)
140+
rec := httptest.NewRecorder()
136141

142+
e.ServeHTTP(rec, req)
143+
144+
assert.Equal(t, http.StatusMovedPermanently, rec.Code)
145+
assert.Equal(t, "", rec.Header().Get(echo.HeaderContentEncoding))
146+
}
147+
148+
func TestGzipWithMinLengthChunked(t *testing.T) {
137149
e := echo.New()
138150

139151
// Gzip chunked
@@ -155,36 +167,36 @@ func TestGzipWithMinLengthChunked(t *testing.T) {
155167
c.Response().Flush()
156168

157169
// Read the first part of the data
158-
assert.True(rec.Flushed)
159-
assert.Equal(gzipScheme, rec.Header().Get(echo.HeaderContentEncoding))
170+
assert.True(t, rec.Flushed)
171+
assert.Equal(t, gzipScheme, rec.Header().Get(echo.HeaderContentEncoding))
160172

161173
var err error
162174
r, err = gzip.NewReader(rec.Body)
163-
assert.NoError(err)
175+
assert.NoError(t, err)
164176

165177
_, err = io.ReadFull(r, chunkBuf)
166-
assert.NoError(err)
167-
assert.Equal("test\n", string(chunkBuf))
178+
assert.NoError(t, err)
179+
assert.Equal(t, "test\n", string(chunkBuf))
168180

169181
// Write and flush the second part of the data
170182
c.Response().Write([]byte("test\n"))
171183
c.Response().Flush()
172184

173185
_, err = io.ReadFull(r, chunkBuf)
174-
assert.NoError(err)
175-
assert.Equal("test\n", string(chunkBuf))
186+
assert.NoError(t, err)
187+
assert.Equal(t, "test\n", string(chunkBuf))
176188

177189
// Write the final part of the data and return
178190
c.Response().Write([]byte("test"))
179191
return nil
180192
})(c)
181193

182-
assert.NotNil(r)
194+
assert.NotNil(t, r)
183195

184196
buf := new(bytes.Buffer)
185197

186198
buf.ReadFrom(r)
187-
assert.Equal("test", buf.String())
199+
assert.Equal(t, "test", buf.String())
188200

189201
r.Close()
190202
}

0 commit comments

Comments
 (0)