check / check (push) Failing after 1s
The http.Server now sets ReadHeaderTimeout (10s), which bounds the slow header dribble that ReadTimeout alone does not, and IdleTimeout (120s), which bounds keep-alive reuse. Server construction moved into a small helper so a test can assert the timeouts without binding a listener. POST / and POST /generate bodies are capped at 1 MiB and an oversized body returns 413. What a reader would trip over: the CSRF library reads its token from the form and swallows a parse error, so a cap applied only inside it would surface as 403. The body limit therefore parses the form under the cap before the CSRF check; the parsed form is reused afterwards. A test covers an oversized body that carries a valid token. Judgement call: WriteTimeout stays at 60s; it also bounds how long a large image may take to send over a slow link. Model: opus-4-8 (implementation, review); fable-5-1 (landing message)
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)
|
|
})
|
|
}
|
|
}
|