mirror of
https://github.com/foomo/keel.git
synced 2025-10-16 12:35:34 +00:00
103 lines
2.2 KiB
Go
103 lines
2.2 KiB
Go
package middleware
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"sync"
|
|
|
|
stdhttp "github.com/foomo/gostandards/http"
|
|
httputils "github.com/foomo/keel/utils/net/http"
|
|
"github.com/klauspost/compress/gzhttp"
|
|
"github.com/klauspost/compress/gzip"
|
|
"github.com/pkg/errors"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type (
|
|
GZipOptions struct {
|
|
CompressionLevel int
|
|
MinSize int
|
|
}
|
|
GZipOption func(*GZipOptions)
|
|
)
|
|
|
|
var DefaultGZipOptions = GZipOptions{
|
|
CompressionLevel: gzip.DefaultCompression,
|
|
MinSize: 1024,
|
|
}
|
|
|
|
// GZipWithLevel allows setting a specific compression level for gzip (default: gzip.DefaultCompression).
|
|
func GZipWithLevel(v int) GZipOption {
|
|
return func(o *GZipOptions) {
|
|
o.CompressionLevel = v
|
|
}
|
|
}
|
|
|
|
// GZipWithMinSize allows setting a minimum response body length to apply gzip compression (default: 1400 bytes).
|
|
func GZipWithMinSize(v int) GZipOption {
|
|
return func(o *GZipOptions) {
|
|
o.MinSize = v
|
|
}
|
|
}
|
|
|
|
// GZip middleware
|
|
func GZip(opts ...GZipOption) Middleware {
|
|
options := DefaultGZipOptions
|
|
for _, opt := range opts {
|
|
if opt != nil {
|
|
opt(&options)
|
|
}
|
|
}
|
|
return GZipWithOptions(options)
|
|
}
|
|
|
|
// GZipWithOptions middleware
|
|
func GZipWithOptions(opts GZipOptions) Middleware {
|
|
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
|
|
pool := sync.Pool{
|
|
New: func() interface{} {
|
|
return new(gzip.Reader)
|
|
},
|
|
}
|
|
wrapper, err := gzhttp.NewWrapper(
|
|
gzhttp.CompressionLevel(opts.CompressionLevel),
|
|
gzhttp.MinSize(opts.MinSize),
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return wrapper(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get(stdhttp.HeaderContentEncoding.String()) != stdhttp.EncodingGzip.String() {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
gr, ok := pool.Get().(*gzip.Reader)
|
|
if !ok {
|
|
httputils.InternalServerError(l, w, r, errors.New("failed to retrieve gzip pool"))
|
|
return
|
|
}
|
|
defer pool.Put(gr)
|
|
|
|
b := r.Body
|
|
defer b.Close()
|
|
|
|
if err := gr.Reset(b); errors.Is(err, io.EOF) {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
} else if err != nil {
|
|
httputils.BadRequestServerError(l, w, r, errors.New("failed to reset gzip"))
|
|
return
|
|
}
|
|
|
|
defer gr.Close()
|
|
|
|
r.Header.Del(stdhttp.HeaderContentEncoding.String())
|
|
|
|
r.Body = gr
|
|
|
|
next.ServeHTTP(w, r)
|
|
}))
|
|
}
|
|
}
|