this repo has no description
at master 2.0 kB view raw
1// httpencoding does on-the-fly zstd or gzip compression of the responses of the wrapped handlers. 2// The handlers it wraps should not do their own compression. 3package httpencoding 4 5import ( 6 "compress/gzip" 7 "io" 8 "net/http" 9 "strconv" 10 "strings" 11 12 "github.com/klauspost/compress/zstd" 13) 14 15// Handler wraps the given handler to return write responses in gzip or zstd content-encoding 16// if the incoming request has the corresponding accept-encoding header. 17func Handler(h http.Handler) http.Handler { 18 return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 19 var acceptGz, acceptZstd float64 20 for _, encQ := range strings.Split(r.Header.Get("accept-encoding"), ",") { 21 enc, qkv, ok := strings.Cut(encQ, ";") 22 var q float64 = 1 23 if ok { 24 litq, qs, ok := strings.Cut(qkv, "=") 25 if litq == "q" && ok { 26 q, _ = strconv.ParseFloat(qs, 64) 27 } 28 } 29 switch strings.TrimSpace(enc) { 30 case "gzip": 31 acceptGz = q 32 case "zstd": 33 acceptZstd = q 34 } 35 } 36 37 if acceptGz == 0 && acceptZstd == 0 { 38 h.ServeHTTP(rw, r) 39 } else if acceptGz > acceptZstd { 40 nrw := newGzip(rw) 41 defer nrw.Flush() 42 rw.Header().Set("content-encoding", "gzip") 43 h.ServeHTTP(nrw, r) 44 } else { 45 nrw := newZstd(rw) 46 defer nrw.Flush() 47 rw.Header().Set("content-encoding", "zstd") 48 h.ServeHTTP(nrw, r) 49 } 50 }) 51} 52 53type encoder interface { 54 io.Writer 55 Flush() error 56} 57 58type responseWriter struct { 59 http.ResponseWriter 60 e encoder 61} 62 63func newGzip(rw http.ResponseWriter) *responseWriter { 64 return &responseWriter{ 65 rw, 66 gzip.NewWriter(rw), 67 } 68} 69 70func newZstd(rw http.ResponseWriter) *responseWriter { 71 e, _ := zstd.NewWriter(rw) 72 return &responseWriter{ 73 rw, 74 e, 75 } 76} 77 78func (r *responseWriter) Flush() { 79 r.e.Flush() 80 if flusher, ok := r.ResponseWriter.(http.Flusher); ok { 81 flusher.Flush() 82 } 83} 84 85func (r *responseWriter) Write(b []byte) (int, error) { 86 return r.e.Write(b) 87} 88 89func (r *responseWriter) Unwrap() http.ResponseWriter { 90 return r.ResponseWriter 91}