package gziphandler import ( "compress/gzip" "io/ioutil" "net/http" "strings" "sync" ) type respWriter struct { http.ResponseWriter w *gzip.Writer } func (w *respWriter) Write(d []byte) (int, error) { return w.w.Write(d) } func (w *respWriter) Close() error { return w.w.Close() } type handler struct { next http.Handler pool sync.Pool } func acceptsGzip(r *http.Request) bool { ae := r.Header.Get("Accept-Encoding") for _, e := range strings.Split(ae, ",") { vals := strings.Split(e, ";") if len(vals) < 1 { continue } if strings.TrimSpace(vals[0]) == "gzip" { return true } } return false } func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !acceptsGzip(r) { h.next.ServeHTTP(w, r) return } w.Header().Set("Content-Encoding", "gzip") gw := h.pool.Get().(*gzip.Writer) gw.Reset(w) rw := &respWriter{ ResponseWriter: w, w: gw, } h.next.ServeHTTP(rw, r) gw.Close() h.pool.Put(gw) } // Handler returns an http.Handler that compresses the response data written // by an existing handler h, using the compress/gzip.Writer with default // compression level. func Handler(h http.Handler) http.Handler { return &handler{ next: h, pool: sync.Pool{ New: func() interface{} { return gzip.NewWriter(ioutil.Discard) }, }, } }