Skip to content

Instantly share code, notes, and snippets.

@corylanou
Created September 16, 2014 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save corylanou/7f5e9db83624cf23f209 to your computer and use it in GitHub Desktop.
Save corylanou/7f5e9db83624cf23f209 to your computer and use it in GitHub Desktop.
package http
import (
"bytes"
"compress/gzip"
"net/http"
"strings"
)
type gzipFilter struct {
http.ResponseWriter
buffer bytes.Buffer
}
func (w *gzipFilter) Write(b []byte) (int, error) {
return w.buffer.Write(b)
}
func GzipFilter(fn http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
filter := &gzipFilter{ResponseWriter: w} // envelope the writer
fn(filter, r) // render the thing we're wrapping / fill our buffer
// set Content-Type if underlying fn has't (they usually should)
if w.Header().Get("Content-Type") == "" {
content := filter.buffer.Bytes()
w.Header().Set("Content-Type", http.DetectContentType(content))
}
// clear Content-Length if underlying fn has set it (they generally do)
if w.Header().Get("Content-Length") != "" {
w.Header().Del("Content-Length")
}
zipper := gzip.NewWriter(w)
defer zipper.Close()
filter.buffer.WriteTo(zipper)
} else {
fn(w, r)
}
}
}
@extemporalgenome
Copy link

Generally you'd want to provide a http.Handler wrapper (takes a Handler, returns a Handler), as that, rather than http.HandlerFunc, is the common currency of http serving in Go.

If you had a GzipFilterer, then GzipFilter could be backwards-compatibly implemented as:

func GzipFilter(fn http.HandlerFunc) http.HandlerFunc {
    return GzipFilterer(fn).ServeContent
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment