check / check (push) Failing after 0s
Add a LimitBody middleware that caps the request body at MaxFormBytes (1 MiB) on POST / and POST /generate and rejects an oversized body with 413. It parses the form under the cap before the CSRF middleware, which reads its token from the body with PostFormValue and would otherwise see a truncated body as a missing token (403); a successful parse is cached, so the CSRF check and handler reuse it. Wired ahead of CSRF in SetupRoutes. This makes the limit explicit rather than resting on ParseForm's incidental 10 MB cap, which would silently vanish if a handler switched to io.ReadAll or multipart. Model: opus-4-8
46 lines
1.5 KiB
Go
46 lines
1.5 KiB
Go
package handlers
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
)
|
|
|
|
// MaxFormBytes bounds the request body accepted on the HTML form POST
|
|
// routes (POST / and POST /generate). The forms carry a handful of short
|
|
// fields, so 1 MiB is generous while making the bound explicit rather than
|
|
// resting on ParseForm's incidental 10 MB cap.
|
|
const MaxFormBytes = 1 << 20 // 1 MiB
|
|
|
|
// LimitBody returns middleware that caps the request body on POST requests
|
|
// at maxBytes and rejects an oversized body with 413 Request Entity Too
|
|
// Large.
|
|
//
|
|
// It parses the form here, before the CSRF middleware reads the token from
|
|
// it. The CSRF middleware reads the token with PostFormValue, which
|
|
// swallows a parse error, so if the body were only capped there an
|
|
// oversized body would read as a missing token and be refused as 403. By
|
|
// parsing under the cap first, an oversized body is refused as 413. A
|
|
// successful parse is cached on the request, so the CSRF check and the
|
|
// handler reuse it rather than reading the body again.
|
|
func (s *Handlers) LimitBody(maxBytes int64) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodPost {
|
|
r.Body = http.MaxBytesReader(w, r.Body, maxBytes)
|
|
|
|
err := r.ParseForm()
|
|
|
|
var tooLarge *http.MaxBytesError
|
|
if errors.As(err, &tooLarge) {
|
|
http.Error(w, "Request body too large",
|
|
http.StatusRequestEntityTooLarge)
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|