roc-lang / roc-lang/basic-webserver

Add a typed, explicit CORS policy evaluator

Open
#201 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
HTML
Stars
107
Forks
20
Avg merge
1d 17h
Merged PRs (30d)
11

Description

Summary

Add a pure Cors module that evaluates actual and preflight requests against an immutable policy.

Illustrative flow:

match Cors.evaluate(policy, request) {
    NotCors => handle(request)
    Preflight(response) => Ok(Server.respond(response))
    Rejected(response) => Ok(Server.respond(response))
    Allowed(cors_headers) => {
        response = handle(request)?
        Ok(Server.respond(Cors.apply(cors_headers, response)?))
    }
}

Why this belongs in the platform

CORS is widely supplied by web-framework middleware, including tower-http. Its header interactions are sufficiently subtle that applications should not independently reproduce them.

It should remain an explicit Roc request/response transformation. It does not require a new middleware runtime or host callback.

Required contract

  • CORS is disabled unless an application constructs and invokes a policy.
  • Exact serialized origins—scheme, host, and port—are the initial allowlist mechanism.
  • Treat the special null origin as denied unless explicitly allowed.
  • Validate requested methods and header names for preflight requests.
  • Support configured exposed headers, credential permission, and bounded preflight max age.
  • Reject policy construction that combines credentialed requests with wildcard origin.
  • Dynamic origin responses merge Vary: Origin case-insensitively without discarding existing Vary values.
  • Access-Control-Allow-Credentials must serialize as lowercase true.
  • Preflight responses do not depend on receiving credentials; browsers do not attach credentials to the preflight itself.
  • Malformed or conflicting Origin fields produce a deterministic denial.
  • The result distinguishes non-CORS, allowed actual, successful preflight, and rejected requests.

Documentation must emphasize that CORS is not CSRF protection. A "simple" cross-origin request can still perform a server-side action even when the browser refuses to expose its response.

Non-goals

  • Regex or suffix origin matching in the first version
  • Guessing trusted origins from Host or forwarded headers
  • CSRF protection
  • Authentication or authorization
  • Applying CORS automatically to native file or operational routes
  • A generic middleware stack

Acceptance criteria

  • Actual and preflight requests are handled from the same validated policy.
  • Wildcard/credentials and Vary behavior follow the Fetch Standard.
  • Origin, method, and header matching have explicit case and normalization rules.
  • No CORS behavior is enabled by default.
  • Real-listener tests cover allowed, denied, credentialed, and cached variants.

References

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the required contract and the linked WHATWG Fetch Standard CORS sections, then locate the repository's Roc request/response types and real-listener test setup. Define the policy and result boundaries before implementation. Done means actual and preflight cases, normalization, wildcard/credential, Vary, disabled-by-default, and cached variants are covered by real-listener tests.

Written by the indexing model from the issue text.

Assessment

Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.