package gzip import ( "compress/gzip" "net/http" "path/filepath" "strings" "github.com/gin-gonic/gin" ) const ( BestCompression = gzip.BestCompression BestSpeed = gzip.BestSpeed DefaultCompression = gzip.DefaultCompression NoCompression = gzip.NoCompression ) func Gzip(level int) gin.HandlerFunc { return func(c *gin.Context) { if !shouldCompress(c.Request) { return } gz, err := gzip.NewWriterLevel(c.Writer, level) if err != nil { return } c.Header("Content-Encoding", "gzip") c.Header("Vary", "Accept-Encoding") c.Writer = &gzipWriter{c.Writer, gz} defer func() { c.Header("Content-Length", "") gz.Close() }() c.Next() } } type gzipWriter struct { gin.ResponseWriter writer *gzip.Writer } func (g *gzipWriter) WriteString(s string) (n int, err error) { return g.writer.Write([]byte(s)) } func (g *gzipWriter) Write(data []byte) (int, error) { return g.writer.Write(data) } func shouldCompress(req *http.Request) bool { if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") { return false } extension := filepath.Ext(req.URL.Path) if len(extension) < 4 { // fast path return true } switch extension { case ".png", ".gif", ".jpeg", ".jpg": return false default: return true } }