1
0
mirror of https://github.com/labstack/echo.git synced 2024-12-22 20:06:21 +02:00
echo/middleware/body_limit.go
2022-02-01 00:48:37 +02:00

95 lines
2.5 KiB
Go

package middleware
import (
"io"
"sync"
"github.com/labstack/echo/v5"
)
// BodyLimitConfig defines the config for BodyLimitWithConfig middleware.
type BodyLimitConfig struct {
// Skipper defines a function to skip middleware.
Skipper Skipper
// LimitBytes is maximum allowed size in bytes for a request body
LimitBytes int64
}
type limitedReader struct {
BodyLimitConfig
reader io.ReadCloser
read int64
context echo.Context
}
// BodyLimit returns a BodyLimit middleware.
//
// BodyLimit middleware sets the maximum allowed size for a request body, if the size exceeds the configured limit, it
// sends "413 - Request Entity Too Large" response. The BodyLimit is determined based on both `Content-Length` request
// header and actual content read, which makes it super secure.
func BodyLimit(limitBytes int64) echo.MiddlewareFunc {
return BodyLimitWithConfig(BodyLimitConfig{LimitBytes: limitBytes})
}
// BodyLimitWithConfig returns a BodyLimitWithConfig middleware. Middleware sets the maximum allowed size in bytes for
// a request body, if the size exceeds the configured limit, it sends "413 - Request Entity Too Large" response.
// The BodyLimitWithConfig is determined based on both `Content-Length` request header and actual content read, which
// makes it super secure.
func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
return toMiddlewareOrPanic(config)
}
// ToMiddleware converts BodyLimitConfig to middleware or returns an error for invalid configuration
func (config BodyLimitConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
if config.Skipper == nil {
config.Skipper = DefaultSkipper
}
pool := sync.Pool{
New: func() interface{} {
return &limitedReader{BodyLimitConfig: config}
},
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if config.Skipper(c) {
return next(c)
}
req := c.Request()
// Based on content length
if req.ContentLength > config.LimitBytes {
return echo.ErrStatusRequestEntityTooLarge
}
// Based on content read
r := pool.Get().(*limitedReader)
r.Reset(c, req.Body)
defer pool.Put(r)
req.Body = r
return next(c)
}
}, nil
}
func (r *limitedReader) Read(b []byte) (n int, err error) {
n, err = r.reader.Read(b)
r.read += int64(n)
if r.read > r.LimitBytes {
return n, echo.ErrStatusRequestEntityTooLarge
}
return
}
func (r *limitedReader) Close() error {
return r.reader.Close()
}
func (r *limitedReader) Reset(context echo.Context, reader io.ReadCloser) {
r.reader = reader
r.context = context
r.read = 0
}