mirror of
https://github.com/labstack/echo.git
synced 2024-12-22 20:06:21 +02:00
95 lines
2.5 KiB
Go
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
|
|
}
|