gzipmiddleware.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package gzipmiddleware
  2. import (
  3. "compress/gzip"
  4. "io"
  5. "net/http"
  6. "strings"
  7. "sync"
  8. )
  9. /*
  10. This module handles web server related helpers and functions
  11. author: tobychui
  12. */
  13. var gzPool = sync.Pool{
  14. New: func() interface{} {
  15. w := gzip.NewWriter(io.Discard)
  16. gzip.NewWriterLevel(w, gzip.BestCompression)
  17. return w
  18. },
  19. }
  20. type gzipResponseWriter struct {
  21. io.Writer
  22. http.ResponseWriter
  23. }
  24. func (w *gzipResponseWriter) WriteHeader(status int) {
  25. //w.Header().Del("Content-Length")
  26. w.ResponseWriter.WriteHeader(status)
  27. }
  28. func (w *gzipResponseWriter) Write(b []byte) (int, error) {
  29. return w.Writer.Write(b)
  30. }
  31. /*
  32. Compresstion function for http.FileServer
  33. */
  34. func Compress(h http.Handler) http.Handler {
  35. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  36. if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
  37. //If the client do not support gzip
  38. h.ServeHTTP(w, r)
  39. return
  40. }
  41. //Handle very special case where it is /share/download
  42. if strings.HasPrefix(r.URL.RequestURI(), "/share/download/") {
  43. h.ServeHTTP(w, r)
  44. return
  45. }
  46. //Check if this is websocket request. Skip this if true
  47. if r.Header["Upgrade"] != nil && r.Header["Upgrade"][0] == "websocket" {
  48. //WebSocket request. Do not gzip it
  49. h.ServeHTTP(w, r)
  50. return
  51. }
  52. //Check if this is Safari. Skip gzip as Catalina Safari dont work with some gzip content
  53. // BETTER IMPLEMENTATION NEEDED
  54. if strings.Contains(r.Header.Get("User-Agent"), "Safari/") {
  55. //Always do not compress for Safari
  56. h.ServeHTTP(w, r)
  57. return
  58. }
  59. w.Header().Set("Content-Encoding", "gzip")
  60. gz := gzPool.Get().(*gzip.Writer)
  61. defer gzPool.Put(gz)
  62. gz.Reset(w)
  63. defer gz.Close()
  64. h.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, r)
  65. })
  66. }
  67. type gzipFuncResponseWriter struct {
  68. io.Writer
  69. http.ResponseWriter
  70. }
  71. func (w gzipFuncResponseWriter) Write(b []byte) (int, error) {
  72. return w.Writer.Write(b)
  73. }
  74. /*
  75. Compress Function for http.HandleFunc
  76. */
  77. func CompressFunc(fn http.HandlerFunc) http.HandlerFunc {
  78. return func(w http.ResponseWriter, r *http.Request) {
  79. if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
  80. fn(w, r)
  81. return
  82. }
  83. w.Header().Set("Content-Encoding", "gzip")
  84. gz := gzip.NewWriter(w)
  85. defer gz.Close()
  86. gzr := gzipFuncResponseWriter{Writer: gz, ResponseWriter: w}
  87. fn(gzr, r)
  88. }
  89. }