diff --git a/gateway/platforms/api_server.py b/gateway/platforms/api_server.py index 0641aca28d..007dd221a4 100644 --- a/gateway/platforms/api_server.py +++ b/gateway/platforms/api_server.py @@ -166,7 +166,7 @@ class ResponseStore: _CORS_HEADERS = { "Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS", - "Access-Control-Allow-Headers": "Authorization, Content-Type", + "Access-Control-Allow-Headers": "Authorization, Content-Type, Idempotency-Key", } diff --git a/tests/gateway/test_api_server.py b/tests/gateway/test_api_server.py index 2ee9284842..020835b367 100644 --- a/tests/gateway/test_api_server.py +++ b/tests/gateway/test_api_server.py @@ -1300,6 +1300,31 @@ class TestCORS: assert "POST" in resp.headers.get("Access-Control-Allow-Methods", "") assert "DELETE" in resp.headers.get("Access-Control-Allow-Methods", "") + @pytest.mark.asyncio + async def test_cors_allows_idempotency_key_header(self): + adapter = _make_adapter(cors_origins=["http://localhost:3000"]) + app = _create_app(adapter) + async with TestClient(TestServer(app)) as cli: + resp = await cli.options( + "/v1/chat/completions", + headers={ + "Origin": "http://localhost:3000", + "Access-Control-Request-Method": "POST", + "Access-Control-Request-Headers": "Idempotency-Key", + }, + ) + assert resp.status == 200 + assert "Idempotency-Key" in resp.headers.get("Access-Control-Allow-Headers", "") + + @pytest.mark.asyncio + async def test_cors_sets_vary_origin_header(self): + adapter = _make_adapter(cors_origins=["http://localhost:3000"]) + app = _create_app(adapter) + async with TestClient(TestServer(app)) as cli: + resp = await cli.get("/health", headers={"Origin": "http://localhost:3000"}) + assert resp.status == 200 + assert resp.headers.get("Vary") == "Origin" + @pytest.mark.asyncio async def test_cors_options_preflight_allowed_for_configured_origin(self): """Configured origins can complete browser preflight."""