github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/http/mws/gzip.go (about) 1 package mws 2 3 import ( 4 "compress/flate" 5 "compress/gzip" 6 "io" 7 "net/http" 8 "strings" 9 ) 10 11 type compressResponseWriter struct { 12 io.Writer 13 http.ResponseWriter 14 http.Hijacker 15 http.Flusher 16 } 17 18 func (w *compressResponseWriter) WriteHeader(c int) { 19 w.ResponseWriter.Header().Del("Content-Length") 20 w.ResponseWriter.WriteHeader(c) 21 } 22 23 func (w *compressResponseWriter) Header() http.Header { 24 return w.ResponseWriter.Header() 25 } 26 27 func (w *compressResponseWriter) Write(b []byte) (int, error) { 28 h := w.ResponseWriter.Header() 29 if h.Get("Content-Type") == "" { 30 h.Set("Content-Type", http.DetectContentType(b)) 31 } 32 h.Del("Content-Length") 33 34 return w.Writer.Write(b) 35 } 36 37 type flusher interface { 38 Flush() error 39 } 40 41 func (w *compressResponseWriter) Flush() { 42 // Flush compressed data if compressor supports it. 43 if f, ok := w.Writer.(flusher); ok { 44 f.Flush() 45 } 46 // Flush HTTP response. 47 if w.Flusher != nil { 48 w.Flusher.Flush() 49 } 50 } 51 52 // CompressHandlerLevel gzip compresses HTTP responses with specified compression level 53 // for clients that support it via the 'Accept-Encoding' header. 54 // 55 // The compression level should be gzip.DefaultCompression, gzip.NoCompression, 56 // or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive. 57 // gzip.DefaultCompression is used in case of invalid compression level. 58 func CompressHandlerLevel(h http.Handler, level int) http.Handler { 59 if level < gzip.DefaultCompression || level > gzip.BestCompression { 60 level = gzip.DefaultCompression 61 } 62 63 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 64 L: 65 for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") { 66 switch strings.TrimSpace(enc) { 67 case "gzip": 68 w.Header().Set("Content-Encoding", "gzip") 69 w.Header().Add("Vary", "Accept-Encoding") 70 71 gw, _ := gzip.NewWriterLevel(w, level) 72 defer gw.Close() 73 74 h, hok := w.(http.Hijacker) 75 if !hok { /* w is not Hijacker... oh well... */ 76 h = nil 77 } 78 79 f, fok := w.(http.Flusher) 80 if !fok { 81 f = nil 82 } 83 84 w = &compressResponseWriter{ 85 Writer: gw, 86 ResponseWriter: w, 87 Hijacker: h, 88 Flusher: f, 89 } 90 91 break L 92 case "deflate": 93 w.Header().Set("Content-Encoding", "deflate") 94 w.Header().Add("Vary", "Accept-Encoding") 95 96 fw, _ := flate.NewWriter(w, level) 97 defer fw.Close() 98 99 h, hok := w.(http.Hijacker) 100 if !hok { /* w is not Hijacker... oh well... */ 101 h = nil 102 } 103 104 f, fok := w.(http.Flusher) 105 if !fok { 106 f = nil 107 } 108 109 w = &compressResponseWriter{ 110 Writer: fw, 111 ResponseWriter: w, 112 Hijacker: h, 113 Flusher: f, 114 } 115 116 break L 117 } 118 } 119 120 h.ServeHTTP(w, r) 121 }) 122 } 123 124 var DefaultCompress = func(h http.Handler) http.Handler { 125 return CompressHandlerLevel(h, gzip.DefaultCompression) 126 }