mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-24 03:05:49 +03:00
Merge pull request #449 from abiosoft/master
Gzip: Fix missing gzip encoding headers.
This commit is contained in:
commit
c748ef944b
4 changed files with 21 additions and 13 deletions
|
@ -57,7 +57,7 @@ outer:
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
defer gzipWriter.Close()
|
defer gzipWriter.Close()
|
||||||
gz := gzipResponseWriter{Writer: gzipWriter, ResponseWriter: w}
|
gz := &gzipResponseWriter{Writer: gzipWriter, ResponseWriter: w}
|
||||||
|
|
||||||
var rw http.ResponseWriter
|
var rw http.ResponseWriter
|
||||||
// if no response filter is used
|
// if no response filter is used
|
||||||
|
@ -104,21 +104,26 @@ func newWriter(c Config, w io.Writer) (*gzip.Writer, error) {
|
||||||
type gzipResponseWriter struct {
|
type gzipResponseWriter struct {
|
||||||
io.Writer
|
io.Writer
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
|
statusCodeWritten bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteHeader wraps the underlying WriteHeader method to prevent
|
// WriteHeader wraps the underlying WriteHeader method to prevent
|
||||||
// problems with conflicting headers from proxied backends. For
|
// problems with conflicting headers from proxied backends. For
|
||||||
// example, a backend system that calculates Content-Length would
|
// example, a backend system that calculates Content-Length would
|
||||||
// be wrong because it doesn't know it's being gzipped.
|
// be wrong because it doesn't know it's being gzipped.
|
||||||
func (w gzipResponseWriter) WriteHeader(code int) {
|
func (w *gzipResponseWriter) WriteHeader(code int) {
|
||||||
w.Header().Del("Content-Length")
|
w.Header().Del("Content-Length")
|
||||||
w.Header().Set("Content-Encoding", "gzip")
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
w.Header().Add("Vary", "Accept-Encoding")
|
w.Header().Add("Vary", "Accept-Encoding")
|
||||||
w.ResponseWriter.WriteHeader(code)
|
w.ResponseWriter.WriteHeader(code)
|
||||||
|
w.statusCodeWritten = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write wraps the underlying Write method to do compression.
|
// Write wraps the underlying Write method to do compression.
|
||||||
func (w gzipResponseWriter) Write(b []byte) (int, error) {
|
func (w *gzipResponseWriter) Write(b []byte) (int, error) {
|
||||||
|
if !w.statusCodeWritten {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
if w.Header().Get("Content-Type") == "" {
|
if w.Header().Get("Content-Type") == "" {
|
||||||
w.Header().Set("Content-Type", http.DetectContentType(b))
|
w.Header().Set("Content-Type", http.DetectContentType(b))
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,6 @@ func TestGzipHandler(t *testing.T) {
|
||||||
|
|
||||||
func nextFunc(shouldGzip bool) middleware.Handler {
|
func nextFunc(shouldGzip bool) middleware.Handler {
|
||||||
return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
|
return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
w.WriteHeader(200)
|
|
||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
if shouldGzip {
|
if shouldGzip {
|
||||||
if r.Header.Get("Accept-Encoding") != "" {
|
if r.Header.Get("Accept-Encoding") != "" {
|
||||||
|
@ -92,7 +91,7 @@ func nextFunc(shouldGzip bool) middleware.Handler {
|
||||||
if w.Header().Get("Vary") != "Accept-Encoding" {
|
if w.Header().Get("Vary") != "Accept-Encoding" {
|
||||||
return 0, fmt.Errorf("Vary must be Accept-Encoding, found %v", r.Header.Get("Vary"))
|
return 0, fmt.Errorf("Vary must be Accept-Encoding, found %v", r.Header.Get("Vary"))
|
||||||
}
|
}
|
||||||
if _, ok := w.(gzipResponseWriter); !ok {
|
if _, ok := w.(*gzipResponseWriter); !ok {
|
||||||
return 0, fmt.Errorf("ResponseWriter should be gzipResponseWriter, found %T", w)
|
return 0, fmt.Errorf("ResponseWriter should be gzipResponseWriter, found %T", w)
|
||||||
}
|
}
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
@ -103,7 +102,7 @@ func nextFunc(shouldGzip bool) middleware.Handler {
|
||||||
if w.Header().Get("Content-Encoding") == "gzip" {
|
if w.Header().Get("Content-Encoding") == "gzip" {
|
||||||
return 0, fmt.Errorf("Content-Encoding must not be gzip, found gzip")
|
return 0, fmt.Errorf("Content-Encoding must not be gzip, found gzip")
|
||||||
}
|
}
|
||||||
if _, ok := w.(gzipResponseWriter); ok {
|
if _, ok := w.(*gzipResponseWriter); ok {
|
||||||
return 0, fmt.Errorf("ResponseWriter should not be gzipResponseWriter")
|
return 0, fmt.Errorf("ResponseWriter should not be gzipResponseWriter")
|
||||||
}
|
}
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
|
|
@ -31,15 +31,16 @@ func (l LengthFilter) ShouldCompress(w http.ResponseWriter) bool {
|
||||||
type ResponseFilterWriter struct {
|
type ResponseFilterWriter struct {
|
||||||
filters []ResponseFilter
|
filters []ResponseFilter
|
||||||
shouldCompress bool
|
shouldCompress bool
|
||||||
gzipResponseWriter
|
statusCodeWritten bool
|
||||||
|
*gzipResponseWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResponseFilterWriter creates and initializes a new ResponseFilterWriter.
|
// NewResponseFilterWriter creates and initializes a new ResponseFilterWriter.
|
||||||
func NewResponseFilterWriter(filters []ResponseFilter, gz gzipResponseWriter) *ResponseFilterWriter {
|
func NewResponseFilterWriter(filters []ResponseFilter, gz *gzipResponseWriter) *ResponseFilterWriter {
|
||||||
return &ResponseFilterWriter{filters: filters, gzipResponseWriter: gz}
|
return &ResponseFilterWriter{filters: filters, gzipResponseWriter: gz}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write wraps underlying Write method and compresses if filters
|
// Write wraps underlying WriteHeader method and compresses if filters
|
||||||
// are satisfied.
|
// are satisfied.
|
||||||
func (r *ResponseFilterWriter) WriteHeader(code int) {
|
func (r *ResponseFilterWriter) WriteHeader(code int) {
|
||||||
// Determine if compression should be used or not.
|
// Determine if compression should be used or not.
|
||||||
|
@ -62,11 +63,15 @@ func (r *ResponseFilterWriter) WriteHeader(code int) {
|
||||||
} else {
|
} else {
|
||||||
r.ResponseWriter.WriteHeader(code)
|
r.ResponseWriter.WriteHeader(code)
|
||||||
}
|
}
|
||||||
|
r.statusCodeWritten = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write wraps underlying Write method and compresses if filters
|
// Write wraps underlying Write method and compresses if filters
|
||||||
// are satisfied
|
// are satisfied
|
||||||
func (r *ResponseFilterWriter) Write(b []byte) (int, error) {
|
func (r *ResponseFilterWriter) Write(b []byte) (int, error) {
|
||||||
|
if !r.statusCodeWritten {
|
||||||
|
r.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
if r.shouldCompress {
|
if r.shouldCompress {
|
||||||
return r.gzipResponseWriter.Write(b)
|
return r.gzipResponseWriter.Write(b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ func TestLengthFilter(t *testing.T) {
|
||||||
for j, filter := range filters {
|
for j, filter := range filters {
|
||||||
r := httptest.NewRecorder()
|
r := httptest.NewRecorder()
|
||||||
r.Header().Set("Content-Length", fmt.Sprint(ts.length))
|
r.Header().Set("Content-Length", fmt.Sprint(ts.length))
|
||||||
wWriter := NewResponseFilterWriter([]ResponseFilter{filter}, gzipResponseWriter{gzip.NewWriter(r), r})
|
wWriter := NewResponseFilterWriter([]ResponseFilter{filter}, &gzipResponseWriter{gzip.NewWriter(r), r, false})
|
||||||
if filter.ShouldCompress(wWriter) != ts.shouldCompress[j] {
|
if filter.ShouldCompress(wWriter) != ts.shouldCompress[j] {
|
||||||
t.Errorf("Test %v: Expected %v found %v", i, ts.shouldCompress[j], filter.ShouldCompress(r))
|
t.Errorf("Test %v: Expected %v found %v", i, ts.shouldCompress[j], filter.ShouldCompress(r))
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,6 @@ func TestResponseFilterWriter(t *testing.T) {
|
||||||
for i, ts := range tests {
|
for i, ts := range tests {
|
||||||
server.Next = middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
|
server.Next = middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
w.Header().Set("Content-Length", fmt.Sprint(len(ts.body)))
|
w.Header().Set("Content-Length", fmt.Sprint(len(ts.body)))
|
||||||
w.WriteHeader(200)
|
|
||||||
w.Write([]byte(ts.body))
|
w.Write([]byte(ts.body))
|
||||||
return 200, nil
|
return 200, nil
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue