roadrunner_cors (roadrunner v0.10.2)
View SourceCross-Origin Resource Sharing (CORS) middleware.
Answers the browser's preflight OPTIONS request and decorates cross-origin
responses with the right Access-Control-* headers, driven by a per-instance
policy. Deny-by-default: a request whose Origin is not allowed gets no
Access-Control-Allow-Origin, so the browser blocks it.
Wire it with its config (there is no useful bare form, origins is required):
middlewares => [
{roadrunner_cors, #{
origins => [~"https://app.example.com"],
methods => [~"GET", ~"POST"],
credentials => true
}}
]Config
| Key | Default | Meaning |
|---|---|---|
origins | (required) | [binary()] allowlist, fun((binary()) -> boolean()) predicate, or any |
methods | [~"GET", ~"HEAD", ~"POST"] | methods echoed in a preflight's Access-Control-Allow-Methods |
headers | [] | [binary()] echoed in Access-Control-Allow-Headers, or reflect to mirror the request's Access-Control-Request-Headers |
expose | [] | [binary()] for Access-Control-Expose-Headers |
credentials | false | when true, emit Access-Control-Allow-Credentials: true |
max_age | (omitted) | preflight cache lifetime in seconds (Access-Control-Max-Age) |
The policy is validated and compiled once when the listener starts (and on
reload_routes/2), so a bad value crashes at startup with
{invalid_cors_opt, Key, Value} rather than failing silently on a request.
Behaviour
- No
Originheader: not a CORS request, passed through untouched. - Preflight (
OPTIONSwithAccess-Control-Request-Method): short-circuited with a204carrying theAccess-Control-*set, without calling the handler. - Simple / actual request: the handler runs, then
Access-Control-Allow-Origin(plus credentials / exposed headers when configured) is added to its response.
Vary: Origin is added to every CORS response, allowed or not, so a shared
cache never serves one origin's response to another; an existing Vary (e.g.
Accept-Encoding from roadrunner_compress) is appended to rather than
replaced.
Credentials and the wildcard
With credentials => true the response echoes the concrete request Origin
rather than *, because a browser rejects Access-Control-Allow-Origin: *
together with Access-Control-Allow-Credentials: true. origins => any
without credentials emits the literal *.
Summary
Types
-type state() :: #cors{origins :: origins(), credentials :: boolean(), reflect_headers :: boolean(), preflight_static :: roadrunner_http:headers(), actual_static :: roadrunner_http:headers()}.
The compiled policy produced by init/1 and consumed by call/3.
Functions
-spec call(roadrunner_req:request(), roadrunner_middleware:next(), state()) -> roadrunner_handler:result().