Skip to content

Commit

Permalink
Fix missing content type on Close
Browse files Browse the repository at this point in the history
If compression had not yet been triggered in Write, be sure to detect content type on Close.

Fixes #882
  • Loading branch information
klauspost committed Nov 10, 2023
1 parent 847c1b4 commit a4a7e17
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
11 changes: 10 additions & 1 deletion gzhttp/compress.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,16 @@ func (w *GzipResponseWriter) Close() error {
ce = w.Header().Get(contentEncoding)
cr = w.Header().Get(contentRange)
)
// fmt.Println(len(w.buf) == 0, len(w.buf) < w.minSize, len(w.Header()[HeaderNoCompression]) != 0, ce != "", cr != "", !w.contentTypeFilter(ct))
if ct == "" {
ct = http.DetectContentType(w.buf)

// Handles the intended case of setting a nil Content-Type (as for http/server or http/fs)
// Set the header only if the key does not exist
if _, ok := w.Header()[contentType]; w.setContentType && !ok {
w.Header().Set(contentType, ct)
}
}

if len(w.buf) == 0 || len(w.buf) < w.minSize || len(w.Header()[HeaderNoCompression]) != 0 || ce != "" || cr != "" || !w.contentTypeFilter(ct) {
// GZIP not triggered, write out regular response.
return w.startPlain()
Expand Down
66 changes: 66 additions & 0 deletions gzhttp/compress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"net/url"
"os"
"strconv"
"strings"
"testing"

"github.com/klauspost/compress/gzip"
Expand Down Expand Up @@ -1883,3 +1884,68 @@ func Test1xxResponses(t *testing.T) {
body, _ := io.ReadAll(res.Body)
assertEqual(t, gzipStrLevel(testBody, gzip.DefaultCompression), body)
}

func TestContentTypeDetectWithJitter(t *testing.T) {
t.Parallel()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
content := `<!DOCTYPE html>` + strings.Repeat("foo", 400)
w.Write([]byte(content))
})

for _, tc := range []struct {
name string
wrapper func(http.Handler) (http.Handler, error)
}{
{
name: "no wrapping",
wrapper: func(h http.Handler) (http.Handler, error) {
return h, nil
},
},
{
name: "default",
wrapper: func(h http.Handler) (http.Handler, error) {
wrapper, err := NewWrapper()
if err != nil {
return nil, err
}
return wrapper(h), nil
},
},
{
name: "jitter, default buffer",
wrapper: func(h http.Handler) (http.Handler, error) {
wrapper, err := NewWrapper(RandomJitter(32, 0, false))
if err != nil {
return nil, err
}
return wrapper(h), nil
},
},
{
name: "jitter, small buffer",
wrapper: func(h http.Handler) (http.Handler, error) {
wrapper, err := NewWrapper(RandomJitter(32, DefaultMinSize, false))
if err != nil {
return nil, err
}
return wrapper(h), nil
},
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

handler, err := tc.wrapper(handler)
assertNil(t, err)

req, resp := httptest.NewRequest(http.MethodGet, "/", nil), httptest.NewRecorder()
req.Header.Add("Accept-Encoding", "gzip")

handler.ServeHTTP(resp, req)

assertEqual(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
})
}
}

0 comments on commit a4a7e17

Please sign in to comment.