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"