Module cors

Module cors 

Source
Expand description

Route-scoped CORS (DW-027, feature analysis 4.14).

Two phases, both driven by one Cors policy attached to a route:

  • Preflight short-circuit (is_preflight + preflight_response): an OPTIONS request carrying BOTH Origin and Access-Control-Request-Method on a CORS-configured route is answered 204 by the gateway immediately after route resolution and the route-scoped limit checks — before authentication, authorization, rate limiting, and cap admission, and NEVER proxied upstream. Browsers send preflights without credentials, so gating them on authn would break every credentialed route; they are also pure metadata probes, so admitting them to the concurrency cap would let a hostile page burn slots cheaply. A preflight that fails validation (origin, method, or requested headers not allowed) is still short-circuited — 204 with NO CORS headers, which the browser reads as a failed preflight. A plain OPTIONS without the preflight markers is NOT intercepted and proxies normally. A preflight whose route match.methods list excludes OPTIONS never resolves the route at all (404, the documented request-path order) — include OPTIONS in the method list of CORS routes.
  • Actual-response decoration (decorate_actual): responses on the route (every action: proxy, redirect, respond) carry Access-Control-Allow-Origin (*, or the echoed request origin under a specific list), Access-Control-Allow-Credentials: true when configured, Access-Control-Expose-Headers when configured, and Vary: Origin (merged; see crate::dataplane::hardening::merge_vary). A request whose Origin is not allowed gets NO CORS headers — the response passes through unchanged (same-origin and no-cors reads never consult CORS).

Origin matching uses the shared origin grammar in crate::config::normalize_origin: exact match on the normalized form (lowercase scheme and host, default port dropped, no userinfo) or the single config entry *. The config side of that comparison is precompiled into crate::config::CompiledCorsOrigins at snapshot-compile time (see crate::snapshot::RouteTable::cors_origins), so the request path normalizes only the request’s own Origin. Subdomain wildcards (*.example.com) are deliberately not offered in v1: an explicit origin list is auditable, a wildcard is not; add entries per origin until that tradeoff is worth revisiting.

Functions§

decorate_actual
Decorate an ACTUAL (non-preflight) response with the route’s CORS headers (DW-027). No-ops when the request carried no Origin or an origin the policy does not allow. origins is the policy’s snapshot-compiled origin set (see preflight_response).
is_preflight
Is this request a CORS preflight (the only request shape the gateway answers without proxying)? Requires OPTIONS, an Origin, and the Access-Control-Request-Method marker the Fetch spec defines for preflights; anything less is a normal request.
preflight_response
Build the gateway-answered preflight response (DW-027): always 204; CORS headers only when the preflight validates against the policy. origins is the policy’s snapshot-compiled origin set (normalized once at compile time, not per request).