Skip to content

feat: add CORS support to gateway#39

Open
ashwing wants to merge 1 commit into
vllm-project:mainfrom
ashwing:feat/cors-support
Open

feat: add CORS support to gateway#39
ashwing wants to merge 1 commit into
vllm-project:mainfrom
ashwing:feat/cors-support

Conversation

@ashwing
Copy link
Copy Markdown
Contributor

@ashwing ashwing commented May 29, 2026

Summary

Wire tower-http CorsLayer into the router with a permissive default (allow any origin, method, and header). This unblocks browser-based clients — playground UIs, Swagger, JS apps — from calling the API directly.

The current default is intentionally permissive (Any) for local development. The code includes a comment proposing two options for production tightening:

  1. Env-driven: CORS_ALLOWED_ORIGINS (comma-separated), fallback to Any
  2. CLI flag: --cors-allow-origin <value> alongside existing gateway args

Happy to implement either in a follow-up based on maintainer preference.

Closes #38

Test Plan

Automated (2 integration tests):

  • test_cors_preflight_returns_200 — OPTIONS with Origin + Access-Control-Request-Method → 200 with all CORS headers
  • test_cors_headers_on_regular_request — POST with Origin → response includes access-control-allow-origin
cargo test --workspace
# 27 tests pass (23 unit + 2 main + 2 CORS)

Lint/format:

  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • cargo fmt -- --check — clean

Discovery: Found via live stress testing against deployed gateway on EC2 (see #38 for reproduction).

Wire tower-http CorsLayer into the router with a permissive default
(allow any origin, method, and header). This unblocks browser-based
clients like playground UIs and Swagger from calling the API directly.

Closes vllm-project#38

Signed-off-by: Ashwin Giridharan <girida@amazon.com>
pub fn build_router(state: ProxyState) -> Router {
// Permissive CORS default — allows any origin for local dev and playground UIs.
// For production, this should be tightened. Two options:
// 1. Env-driven: read CORS_ALLOWED_ORIGINS (comma-separated), fall back to Any
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's create a ServerConfig struct and add there, yeah? we can pass it to the build_router function.

something like:

impl ServerConfig {
    /// Read `CORS_ALLOWED_ORIGINS` (comma-separated). Unset or empty = permissive.
    pub fn from_env() -> Self {
        let cors_allowed_origins = std::env::var("CORS_ALLOWED_ORIGINS")
            .ok()
            .map(|s| {
                s.split(',')
                    .map(str::trim)
                    .filter(|o| !o.is_empty())
                    .map(str::to_owned)
                    .collect::<Vec<_>>()
            })
            .unwrap_or_default();
        Self { cors_allowed_origins }
    }
}

would be good to update the docs with this as setting here would default to permissive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add CORS support to gateway

2 participants