Phase 14: Security + Storage#
Implement Cross-Origin Resource Sharing (CORS) per the Fetch Standard to allow controlled cross-origin access.
Background#
Depends on: Same-Origin Policy enforcement.
CORS relaxes the Same-Origin Policy for specific requests. When a cross-origin fetch is made, the browser must check Access-Control-* response headers to determine whether the response should be exposed to the requesting script.
Requirements#
Simple requests (no preflight)#
- Identify simple requests: method is GET/HEAD/POST, headers are CORS-safelisted, and Content-Type (if present) is application/x-www-form-urlencoded, multipart/form-data, or text/plain
- For simple cross-origin requests, send the Origin request header
- On response, check Access-Control-Allow-Origin -- if it matches the request origin or is *, expose the response; otherwise block it
- Respect Access-Control-Expose-Headers to determine which response headers are visible to the script
Preflight requests#
- For non-simple cross-origin requests, send an OPTIONS preflight before the actual request
- Include Access-Control-Request-Method and Access-Control-Request-Headers in the preflight
- Parse the preflight response: Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Max-Age
- Cache preflight results per (origin, URL, max-age) to avoid redundant preflights
- Only proceed with the actual request if the preflight succeeds
Credentialed requests#
- Support credentials: include mode on Fetch/XHR
- When credentials are included, Access-Control-Allow-Origin must not be * -- it must echo the exact origin
- Check Access-Control-Allow-Credentials: true on the response
- Include cookies (from the cookie jar, once implemented) in credentialed cross-origin requests
Integration points#
- crates/net/src/http.rs: add Origin header serialization
- crates/net/src/client.rs: implement CORS preflight logic and cache
- crates/browser/src/loader.rs: integrate CORS checks into resource loading pipeline
- crates/js: wire CORS mode into the Fetch API bridge
Acceptance Criteria#
- Simple cross-origin GET with Access-Control-Allow-Origin: * succeeds
- Simple cross-origin GET without CORS headers is blocked
- Non-simple request triggers OPTIONS preflight before actual request
- Preflight cache avoids redundant OPTIONS for subsequent requests within max-age
- Credentialed request requires exact origin echo and Allow-Credentials: true
- Access-Control-Expose-Headers controls which headers are visible
- cargo clippy --workspace -- -D warnings passes
- cargo test --workspace passes