handler.go (1643B)
1 package gzip 2 3 import ( 4 "compress/gzip" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "path/filepath" 9 "strings" 10 "sync" 11 12 "github.com/gin-gonic/gin" 13 ) 14 15 type gzipHandler struct { 16 *Options 17 gzPool sync.Pool 18 } 19 20 func newGzipHandler(level int, options ...Option) *gzipHandler { 21 handler := &gzipHandler{ 22 Options: DefaultOptions, 23 gzPool: sync.Pool{ 24 New: func() interface{} { 25 gz, err := gzip.NewWriterLevel(ioutil.Discard, level) 26 if err != nil { 27 panic(err) 28 } 29 return gz 30 }, 31 }, 32 } 33 for _, setter := range options { 34 setter(handler.Options) 35 } 36 return handler 37 } 38 39 func (g *gzipHandler) Handle(c *gin.Context) { 40 if fn := g.DecompressFn; fn != nil && c.Request.Header.Get("Content-Encoding") == "gzip" { 41 fn(c) 42 } 43 44 if !g.shouldCompress(c.Request) { 45 return 46 } 47 48 gz := g.gzPool.Get().(*gzip.Writer) 49 defer g.gzPool.Put(gz) 50 defer gz.Reset(ioutil.Discard) 51 gz.Reset(c.Writer) 52 53 c.Header("Content-Encoding", "gzip") 54 c.Header("Vary", "Accept-Encoding") 55 c.Writer = &gzipWriter{c.Writer, gz} 56 defer func() { 57 gz.Close() 58 c.Header("Content-Length", fmt.Sprint(c.Writer.Size())) 59 }() 60 c.Next() 61 } 62 63 func (g *gzipHandler) shouldCompress(req *http.Request) bool { 64 if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") || 65 strings.Contains(req.Header.Get("Connection"), "Upgrade") || 66 strings.Contains(req.Header.Get("Accept"), "text/event-stream") { 67 return false 68 } 69 70 extension := filepath.Ext(req.URL.Path) 71 if g.ExcludedExtensions.Contains(extension) { 72 return false 73 } 74 75 if g.ExcludedPaths.Contains(req.URL.Path) { 76 return false 77 } 78 if g.ExcludedPathesRegexs.Contains(req.URL.Path) { 79 return false 80 } 81 82 return true 83 }