#4759 introducing a general body limit to avoid big heap allocations

This commit is contained in:
Maximilian Pfeffer 2026-07-27 22:16:33 +02:00
parent 34dac209ff
commit ad91108a5b
2 changed files with 28 additions and 4 deletions

View File

@ -940,6 +940,7 @@ func (c *Context) ShouldBindUri(obj any) error {
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
// See the binding package.
func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
c.limitRequestBody()
return b.Bind(c.Request, obj)
}
@ -949,6 +950,7 @@ func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
// NOTE: This method reads the body before binding. So you should use
// ShouldBindWith for better performance if you need to call only once.
func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error) {
c.limitRequestBody()
var body []byte
if cb, ok := c.Get(BodyBytesKey); ok {
if cbb, ok := cb.([]byte); ok {
@ -965,6 +967,19 @@ func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error
return bb.BindBody(body, obj)
}
// limitRequestBody wraps c.Request.Body in place so that reading more than
// c.engine.MaxRequestBodyBytes from it fails with *http.MaxBytesError, which
// MustBindWith already maps to a 413 response.
func (c *Context) limitRequestBody() {
if c.engine == nil || c.engine.MaxRequestBodyBytes <= 0 {
return
}
if c.Request == nil || c.Request.Body == nil {
return
}
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, c.engine.MaxRequestBodyBytes)
}
// ShouldBindBodyWithJSON is a shortcut for c.ShouldBindBodyWith(obj, binding.JSON).
func (c *Context) ShouldBindBodyWithJSON(obj any) error {
return c.ShouldBindBodyWith(obj, binding.JSON)

17
gin.go
View File

@ -23,10 +23,11 @@ import (
)
const (
defaultMultipartMemory = 32 << 20 // 32 MB
escapedColon = "\\:"
colon = ":"
backslash = "\\"
defaultMultipartMemory = 32 << 20 // 32 MB
defaultMaxRequestBodyBytes = 128 << 20 // 128 MiB
escapedColon = "\\:"
colon = ":"
backslash = "\\"
)
var (
@ -166,6 +167,13 @@ type Engine struct {
// method call.
MaxMultipartMemory int64
// MaxRequestBodyBytes limits how many bytes Context's Bind*/ShouldBind*/
// ShouldBindBodyWith* methods will read from a request body before failing
// with a 413. It protects against a client sending an oversized or
// malformed body that would otherwise be buffered into memory in full
// before being rejected. Set to <= 0 to disable and read bodies unbounded.
MaxRequestBodyBytes int64
// UseH2C enable h2c support.
UseH2C bool
@ -219,6 +227,7 @@ func New(opts ...OptionFunc) *Engine {
RemoveExtraSlash: false,
UnescapePathValues: true,
MaxMultipartMemory: defaultMultipartMemory,
MaxRequestBodyBytes: defaultMaxRequestBodyBytes,
trees: make(methodTrees, 0, 9),
delims: render.Delims{Left: "{{", Right: "}}"},
secureJSONPrefix: "while(1);",