handler.go 1.4 KB

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