Refusing CORS simple requests — the cross-origin POSTs a browser sends
without asking first.
A cross-origin fetch or form POST skips the CORS preflight when its
Content-Type is absent or one of the three CORS-safelisted types
(text/plain, application/x-www-form-urlencoded, multipart/form-data).
The browser sends such a request as-is, with whatever cookies apply — only
the response is withheld from the page. Any other content type makes the
browser send an OPTIONS preflight first, and since fuz_app answers no
preflight with CORS headers, the real request is never sent.
The session cookie's SameSite=Strict doesn't close this on its own:
same-site ignores the port, so a page on http://localhost:8000 is
same-site with a server on http://localhost:4460 and its requests carry
the cookie. The origin allowlist (http/origin.ts) refuses such a page
unless a wildcard (http://localhost:*) admits it; this gate refuses it
whatever the allowlist says.
So every POST route carries a content-type check, run first by
apply_route_specs (is_post_content_type_refused, 415
unsupported_content_type): a JSON route takes only application/json,
bodyless or not, and a raw_body route takes any type that isn't
safelisted. Only POST needs it: PUT, PATCH, and DELETE are never
simple methods, so the browser always preflights them.
The check rests on the server answering no preflight. A consumer that adds
CORS middleware granting cross-origin requests reopens what this closes.
Twin of the Rust spine's fuz_http::simple_request: the same predicates,
is_json_content_type checked in each spine JSON handler and
is_cors_simple_content_type by the simple_request_layer consumers mount
over routes with other bodies.