MCPcopy Create free account
hub / github.com/PerpetualSoftware/pad / decodeJSONWithLimit

Function decodeJSONWithLimit

internal/server/server.go:2194–2236  ·  view source on GitHub ↗

decodeJSONWithLimit is the size-configurable variant. Use this for endpoints that accept large payloads (e.g. bulk-import) where the default cap is too small — but always pass an explicit cap, never remove the wrapper.

(r *http.Request, v interface{}, maxBytes int64)

Source from the content-addressed store, hash-verified

2192// default cap is too small — but always pass an explicit cap, never
2193// remove the wrapper.
2194func decodeJSONWithLimit(r *http.Request, v interface{}, maxBytes int64) error {
2195 raw, err := readBodyForDecode(r, maxBytes)
2196 if err != nil {
2197 return fmt.Errorf("invalid JSON: %w", err)
2198 }
2199 // An EMPTY (or whitespace-only) body must keep returning a wrapped
2200 // io.EOF. json.Decoder.Decode answered io.EOF there and at least one
2201 // caller depends on it — handlers_playbooks.go treats
2202 // errors.Is(err, io.EOF) as "no arguments supplied" and runs anyway —
2203 // while json.Unmarshal answers a SyntaxError instead, which that check
2204 // cannot see. Found by TestPlaybookRunAcceptsEmptyBody, which is exactly
2205 // the wiring a helper-level change is blind to.
2206 // Trim only the four bytes JSON itself calls whitespace. bytes.TrimSpace
2207 // uses unicode.IsSpace, which also strips \v, \f, U+00A0 and friends —
2208 // none of which encoding/json accepts. With TrimSpace a body of just
2209 // "\v" looked EMPTY here and returned io.EOF, so an EOF-tolerant caller
2210 // (playbook run, share links) treated a syntactically invalid body as an
2211 // ABSENT one and proceeded. Same Go-versus-spec whitespace divergence
2212 // that bites when a Go trim stands in for another grammar's definition
2213 // (codex round 22).
2214 if len(bytes.Trim(raw, " \t\r\n")) == 0 {
2215 return fmt.Errorf("invalid JSON: %w", io.EOF)
2216 }
2217 // Refuse a decoded NUL BEFORE unmarshalling, so the value never exists
2218 // in a Go string that a handler could hand to the store. See
2219 // bodyDecodesNUL for why the body needs its own rule and why the check
2220 // cannot be a substring search. BUG-2803.
2221 if bodyDecodesNUL(raw) {
2222 return errJSONBodyNUL
2223 }
2224 // json.Unmarshal rather than a Decoder over the buffer: it is the
2225 // cheaper of the two by ~2x in total allocation (see readBodyForDecode's
2226 // measurement), and it REFUSES trailing non-whitespace after the JSON
2227 // value where Decode silently ignores it. That second difference is a
2228 // deliberate behaviour change in the same direction as this fix —
2229 // malformed input is refused at the door rather than partly consumed —
2230 // and it is the only compatibility change in BUG-2803. Trailing
2231 // whitespace, which real clients do send, is still accepted.
2232 if err := json.Unmarshal(raw, v); err != nil {
2233 return fmt.Errorf("invalid JSON: %w", err)
2234 }
2235 return nil
2236}
2237
2238// errJSONBodyNUL is returned by decodeJSON when a string in the request body
2239// decodes to a value containing a NUL. Every decodeJSON caller already turns

Callers 3

decodeJSONFunction · 0.85
handleImportWorkspaceMethod · 0.85

Calls 2

readBodyForDecodeFunction · 0.85
bodyDecodesNULFunction · 0.85

Tested by 1