mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
6d9e043284
This reintroduces support for Go modules, as v4. CloseNotifier() is removed as it has been obsoleted, see https://golang.org/doc/go1.11#net/http It was already NOT working (not sending signals) as of 1.11 the functionality was gone, we merely deleted the functions that exposed it. If anyone still relies on it they should migrate to using `c.Request().Context().Done()` instead. Closes #1268, #1255
118 lines
2.7 KiB
Go
118 lines
2.7 KiB
Go
package middleware
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"sync"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/labstack/gommon/bytes"
|
|
)
|
|
|
|
type (
|
|
// BodyLimitConfig defines the config for BodyLimit middleware.
|
|
BodyLimitConfig struct {
|
|
// Skipper defines a function to skip middleware.
|
|
Skipper Skipper
|
|
|
|
// Maximum allowed size for a request body, it can be specified
|
|
// as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P.
|
|
Limit string `yaml:"limit"`
|
|
limit int64
|
|
}
|
|
|
|
limitedReader struct {
|
|
BodyLimitConfig
|
|
reader io.ReadCloser
|
|
read int64
|
|
context echo.Context
|
|
}
|
|
)
|
|
|
|
var (
|
|
// DefaultBodyLimitConfig is the default BodyLimit middleware config.
|
|
DefaultBodyLimitConfig = BodyLimitConfig{
|
|
Skipper: DefaultSkipper,
|
|
}
|
|
)
|
|
|
|
// 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.
|
|
// Limit can be specified as `4x` or `4xB`, where x is one of the multiple from K, M,
|
|
// G, T or P.
|
|
func BodyLimit(limit string) echo.MiddlewareFunc {
|
|
c := DefaultBodyLimitConfig
|
|
c.Limit = limit
|
|
return BodyLimitWithConfig(c)
|
|
}
|
|
|
|
// BodyLimitWithConfig returns a BodyLimit middleware with config.
|
|
// See: `BodyLimit()`.
|
|
func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
|
|
// Defaults
|
|
if config.Skipper == nil {
|
|
config.Skipper = DefaultBodyLimitConfig.Skipper
|
|
}
|
|
|
|
limit, err := bytes.Parse(config.Limit)
|
|
if err != nil {
|
|
panic(fmt.Errorf("echo: invalid body-limit=%s", config.Limit))
|
|
}
|
|
config.limit = limit
|
|
pool := limitedReaderPool(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.limit {
|
|
return echo.ErrStatusRequestEntityTooLarge
|
|
}
|
|
|
|
// Based on content read
|
|
r := pool.Get().(*limitedReader)
|
|
r.Reset(req.Body, c)
|
|
defer pool.Put(r)
|
|
req.Body = r
|
|
|
|
return next(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *limitedReader) Read(b []byte) (n int, err error) {
|
|
n, err = r.reader.Read(b)
|
|
r.read += int64(n)
|
|
if r.read > r.limit {
|
|
return n, echo.ErrStatusRequestEntityTooLarge
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *limitedReader) Close() error {
|
|
return r.reader.Close()
|
|
}
|
|
|
|
func (r *limitedReader) Reset(reader io.ReadCloser, context echo.Context) {
|
|
r.reader = reader
|
|
r.context = context
|
|
r.read = 0
|
|
}
|
|
|
|
func limitedReaderPool(c BodyLimitConfig) sync.Pool {
|
|
return sync.Pool{
|
|
New: func() interface{} {
|
|
return &limitedReader{BodyLimitConfig: c}
|
|
},
|
|
}
|
|
}
|