gzip.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. package gzip
  2. import (
  3. "compress/gzip"
  4. "net/http"
  5. "path/filepath"
  6. "strings"
  7. "github.com/gin-gonic/gin"
  8. )
  9. const (
  10. BestCompression = gzip.BestCompression
  11. BestSpeed = gzip.BestSpeed
  12. DefaultCompression = gzip.DefaultCompression
  13. NoCompression = gzip.NoCompression
  14. )
  15. func Gzip(level int) gin.HandlerFunc {
  16. return func(c *gin.Context) {
  17. if !shouldCompress(c.Request) {
  18. return
  19. }
  20. gz, err := gzip.NewWriterLevel(c.Writer, level)
  21. if err != nil {
  22. return
  23. }
  24. c.Header("Content-Encoding", "gzip")
  25. c.Header("Vary", "Accept-Encoding")
  26. c.Writer = &gzipWriter{c.Writer, gz}
  27. defer func() {
  28. c.Header("Content-Length", "0")
  29. gz.Close()
  30. }()
  31. c.Next()
  32. }
  33. }
  34. type gzipWriter struct {
  35. gin.ResponseWriter
  36. writer *gzip.Writer
  37. }
  38. func (g *gzipWriter) WriteString(s string) (int, error) {
  39. return g.writer.Write([]byte(s))
  40. }
  41. func (g *gzipWriter) Write(data []byte) (int, error) {
  42. return g.writer.Write(data)
  43. }
  44. func shouldCompress(req *http.Request) bool {
  45. if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
  46. return false
  47. }
  48. extension := filepath.Ext(req.URL.Path)
  49. if len(extension) < 4 { // fast path
  50. return true
  51. }
  52. switch extension {
  53. case ".png", ".gif", ".jpeg", ".jpg":
  54. return false
  55. default:
  56. return true
  57. }
  58. }