jsonbody

package
v0.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package jsonbody is how a cloop HTTP handler reads a JSON request body — the only way, in pkg/ui and pkg/apiserver alike (Task 20394).

Before it, every handler decoded r.Body itself, and every one of them decoded it as JSON whatever its Content-Type said. That turns out to be the detail a cross-site request forgery needs: a form with enctype=text/plain, or fetch() in no-cors mode, sends a body a page on another origin chose — `{"title":"…","x":"=…"}` is a perfectly good text/plain form field — without asking the server first. A browser asks first (a CORS preflight, which the hub never grants) only for a content type outside the three a form can produce. So an endpoint that accepts nothing but application/json cannot be reached by a page elsewhere at all, whatever else goes wrong.

What Decode does, in order:

  • A Content-Type that is not application/json is refused with 415 before the body is read.
  • The body is read up to the limit; past it, 413.
  • An empty body is the handler's defaults when it said the body is optional, and 400 otherwise. A body is not empty here just because Content-Length said so: a chunked request has none.
  • A body with no Content-Type at all is refused with 415. A browser can send one (fetch with a Blob of no type), and it would otherwise be the way around the first rule.
  • Anything that does not decode into dst is 400.

Every refusal is written here, as a pkg/apierror body, so a handler that sees false has nothing left to say.

Index

Constants

View Source
const DefaultLimit int64 = 10 << 20

DefaultLimit is the cap when Options.Limit is zero: 10 MiB, generous enough for a chat transcript or a bulk task edit.

Variables

This section is empty.

Functions

func Decode

func Decode(w http.ResponseWriter, r *http.Request, dst any, o Options) bool

Decode reads r's JSON body into dst. It reports whether the handler may continue; when it may not, the response has been written.

func IsMediaType

func IsMediaType(contentType string, types ...string) bool

IsMediaType reports whether contentType names one of types, parameters aside and case insensitively.

func MediaTypeMessage

func MediaTypeMessage(sent string, also ...string) string

MediaTypeMessage is the sentence a 415 carries: what was sent, what is taken, and why the hub is strict about it. Exported so the middleware that refuses a form body before any handler runs says the same thing.

func Read

Read applies Decode's rules — the media type, the size limit, a required body — and returns the body undecoded, or the refusal Decode would have written. An optional body that is empty is returned as nil.

For a handler that answers its refusals in a dialect of its own: the SCIM routes (Task 20415) speak RFC 7644's error document to identity providers, and take application/scim+json, but read their bodies here like every other handler, so the rules a cross-site form cannot satisfy hold for them too.

Types

type Options

type Options struct {
	// Limit caps the body in bytes; zero is DefaultLimit.
	Limit int64
	// Optional lets the body be empty, which leaves dst untouched — the
	// handler's defaults. A non-empty body must still be JSON.
	Optional bool
	// Strict refuses fields dst does not declare.
	Strict bool
	// MediaTypes are JSON media types the body may carry besides
	// application/json. A browser sends its Content-Security-Policy reports
	// as application/csp-report or application/reports+json, which a form on
	// another page cannot produce either (Task 20408). The body still decodes
	// as JSON.
	MediaTypes []string
}

Options describes how one handler reads its body. The zero value is a required body of at most DefaultLimit.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL