gzipmiddleware.go 2.3 KB

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