Bier.Plugs.Cors (bier v0.1.0)

Copy Markdown View Source

CORS middleware mirroring PostgREST's server-cors-allowed-origins (PostgREST src/PostgREST/Cors.hs).

CORS headers are emitted only when the request carries an Origin header; a request without Origin is a same-origin request and gets no CORS headers (PostgREST's corsPolicy returns Nothing when no Origin is present).

Origin matching follows the WAI cors middleware semantics PostgREST relies on:

  • Allowlist configured (server-cors-allowed-origins is a non-empty, comma-separated list): a request whose Origin is in the list gets that origin echoed in Access-Control-Allow-Origin together with Access-Control-Allow-Credentials: true. An Origin not in the list gets no Access-Control-Allow-Origin header.
  • Empty/unset ("" or nil): every origin is allowed, so Access-Control-Allow-Origin: * is returned (no credentials, per the WAI wildcard rule).

For a CORS preflight (OPTIONS carrying Access-Control-Request-Method) the response additionally advertises the allowed methods, headers, and a 24h max-age — the fixed set PostgREST configures, widened by the WAI middleware's union with the CORS "simple" methods and headers. Access-Control-Allow-Headers is emitted only when the preflight actually carried Access-Control-Request-Headers: wai-cors' hdrRequestHeader returns no header at all for the Nothing case (see put_allow_headers/1).

This plug sets no Vary header of its own. It would suppress the v16 default on exactly the requests that carry an Originput_resp_header/3 replaces, and Bier.Plugs.Vary's funnel skips a response that already has a Vary. Instead the funnel reads the Access-Control-Allow-Origin this plug wrote and appends Origin to the default when the value is an echo rather than the wildcard, so a CORS response carries the union Vary: Accept, Prefer, Range, Origin. That is a deliberate divergence from PostgREST, which builds its policy with corsVaryOrigin = False (Cors.hs) and therefore names no Vary at all on a response whose Access-Control-Allow-Origin depends on the request — see #98 and the README's "Deliberate divergences from PostgREST".

Summary

Functions

True when the request is a CORS preflight: an OPTIONS carrying Access-Control-Request-Method.

Functions

preflight?(conn)

@spec preflight?(Plug.Conn.t()) :: boolean()

True when the request is a CORS preflight: an OPTIONS carrying Access-Control-Request-Method.

Public so Bier.Plugs.Vary can leave preflight responses alone without restating the predicate — upstream answers a preflight inside the wai-cors middleware, before the funnel that appends Vary runs at all.