| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 | package middlewareimport (	"bufio"	"compress/gzip"	"io"	"io/ioutil"	"net"	"net/http"	"strings"	"github.com/labstack/echo")type (	// GzipConfig defines the config for Gzip middleware.	GzipConfig struct {		// Skipper defines a function to skip middleware.		Skipper Skipper		// Gzip compression level.		// Optional. Default value -1.		Level int `yaml:"level"`	}	gzipResponseWriter struct {		io.Writer		http.ResponseWriter	})const (	gzipScheme = "gzip")var (	// DefaultGzipConfig is the default Gzip middleware config.	DefaultGzipConfig = GzipConfig{		Skipper: DefaultSkipper,		Level:   -1,	})// Gzip returns a middleware which compresses HTTP response using gzip compression// scheme.func Gzip() echo.MiddlewareFunc {	return GzipWithConfig(DefaultGzipConfig)}// GzipWithConfig return Gzip middleware with config.// See: `Gzip()`.func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {	// Defaults	if config.Skipper == nil {		config.Skipper = DefaultGzipConfig.Skipper	}	if config.Level == 0 {		config.Level = DefaultGzipConfig.Level	}	return func(next echo.HandlerFunc) echo.HandlerFunc {		return func(c echo.Context) error {			if config.Skipper(c) {				return next(c)			}			res := c.Response()			res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)			if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {				res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806				rw := res.Writer				w, err := gzip.NewWriterLevel(rw, config.Level)				if err != nil {					return err				}				defer func() {					if res.Size == 0 {						if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {							res.Header().Del(echo.HeaderContentEncoding)						}						// We have to reset response to it's pristine state when						// nothing is written to body or error is returned.						// See issue #424, #407.						res.Writer = rw						w.Reset(ioutil.Discard)					}					w.Close()				}()				grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}				res.Writer = grw			}			return next(c)		}	}}func (w *gzipResponseWriter) WriteHeader(code int) {	if code == http.StatusNoContent { // Issue #489		w.ResponseWriter.Header().Del(echo.HeaderContentEncoding)	}	w.Header().Del(echo.HeaderContentLength) // Issue #444	w.ResponseWriter.WriteHeader(code)}func (w *gzipResponseWriter) Write(b []byte) (int, error) {	if w.Header().Get(echo.HeaderContentType) == "" {		w.Header().Set(echo.HeaderContentType, http.DetectContentType(b))	}	return w.Writer.Write(b)}func (w *gzipResponseWriter) Flush() {	w.Writer.(*gzip.Writer).Flush()}func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {	return w.ResponseWriter.(http.Hijacker).Hijack()}func (w *gzipResponseWriter) CloseNotify() <-chan bool {	return w.ResponseWriter.(http.CloseNotifier).CloseNotify()}
 |