mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
Adding sync.Pool to Decompress middleware
Fixing a http.Request.Body leak on the decompress middleware that were not properly Close Removing the defer on the call to gzip.Reader, because that reader is already exausted after the call to io.Copy
This commit is contained in:
parent
502cce28d5
commit
14e020bc07
@ -59,7 +59,7 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
|||||||
config.Level = DefaultGzipConfig.Level
|
config.Level = DefaultGzipConfig.Level
|
||||||
}
|
}
|
||||||
|
|
||||||
pool := gzipPool(config)
|
pool := gzipCompressPool(config)
|
||||||
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
@ -133,7 +133,7 @@ func (w *gzipResponseWriter) Push(target string, opts *http.PushOptions) error {
|
|||||||
return http.ErrNotSupported
|
return http.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func gzipPool(config GzipConfig) sync.Pool {
|
func gzipCompressPool(config GzipConfig) sync.Pool {
|
||||||
return sync.Pool{
|
return sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
w, err := gzip.NewWriterLevel(ioutil.Discard, config.Level)
|
w, err := gzip.NewWriterLevel(ioutil.Discard, config.Level)
|
||||||
|
@ -3,9 +3,12 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -32,27 +35,63 @@ func Decompress() echo.MiddlewareFunc {
|
|||||||
//DecompressWithConfig decompresses request body based if content encoding type is set to "gzip" with config
|
//DecompressWithConfig decompresses request body based if content encoding type is set to "gzip" with config
|
||||||
func DecompressWithConfig(config DecompressConfig) echo.MiddlewareFunc {
|
func DecompressWithConfig(config DecompressConfig) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
pool := gzipDecompressPool()
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
if config.Skipper(c) {
|
if config.Skipper(c) {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
switch c.Request().Header.Get(echo.HeaderContentEncoding) {
|
switch c.Request().Header.Get(echo.HeaderContentEncoding) {
|
||||||
case GZIPEncoding:
|
case GZIPEncoding:
|
||||||
gr, err := gzip.NewReader(c.Request().Body)
|
b := c.Request().Body
|
||||||
if err != nil {
|
|
||||||
|
i := pool.Get()
|
||||||
|
gr, ok := i.(*gzip.Reader)
|
||||||
|
if !ok {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, i.(error).Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gr.Reset(b); err != nil {
|
||||||
|
pool.Put(gr)
|
||||||
if err == io.EOF { //ignore if body is empty
|
if err == io.EOF { //ignore if body is empty
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer gr.Close()
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
io.Copy(&buf, gr)
|
io.Copy(&buf, gr)
|
||||||
|
|
||||||
|
gr.Close()
|
||||||
|
pool.Put(gr)
|
||||||
|
|
||||||
|
b.Close() // http.Request.Body is closed by the Server, but because we are replacing it, it must be closed here
|
||||||
|
|
||||||
r := ioutil.NopCloser(&buf)
|
r := ioutil.NopCloser(&buf)
|
||||||
defer r.Close()
|
|
||||||
c.Request().Body = r
|
c.Request().Body = r
|
||||||
}
|
}
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gzipDecompressPool() sync.Pool {
|
||||||
|
return sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
// create with an empty reader (but with GZIP header)
|
||||||
|
w, err := gzip.NewWriterLevel(ioutil.Discard, gzip.BestSpeed)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
w.Reset(b)
|
||||||
|
w.Flush()
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
r, err := gzip.NewReader(bytes.NewReader(b.Bytes()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user