The template's files at a77fd30, without its history or LICENSE, after script/rename simplexcalc. Model: opus-5-5
47 lines
1.5 KiB
Go
47 lines
1.5 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
// BodyLimit caps how much of a request body a handler can read.
|
|
//
|
|
// http.MaxBytesReader is the mechanism, and the reason to use it rather
|
|
// than checking Content-Length is that Content-Length is a claim: a
|
|
// chunked request does not send one, and a lying one is trivial to
|
|
// send. MaxBytesReader counts the bytes that actually arrive and makes
|
|
// the read fail past the cap, so the ceiling holds whatever the headers
|
|
// said.
|
|
//
|
|
// It also sets the response's error status itself (413) when the limit
|
|
// is hit during a read, so a handler that ignores the read error still
|
|
// cannot serve a success off a truncated body.
|
|
//
|
|
// Content-Length is still checked first, as an early refusal: it costs
|
|
// nothing and it lets an oversized upload be rejected before it is
|
|
// transferred.
|
|
func (m *Middleware) BodyLimit() func(http.Handler) http.Handler {
|
|
limit := m.cfg.MaxRequestBody
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.ContentLength > limit {
|
|
w.Header().Set("Content-Length", strconv.Itoa(len(tooLargeBody)))
|
|
http.Error(w, tooLargeBody, http.StatusRequestEntityTooLarge)
|
|
|
|
return
|
|
}
|
|
|
|
r.Body = http.MaxBytesReader(w, r.Body, limit)
|
|
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|
|
|
|
// tooLargeBody is the response to an oversized request. It names no
|
|
// limit: the number is an operational detail and telling a caller
|
|
// exactly where the ceiling is only helps them sit under it.
|
|
const tooLargeBody = "request body too large"
|