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  }