-
Notifications
You must be signed in to change notification settings - Fork 554
(fix)Add CORS support for direct open browser-based frontends (studio.html) #404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Problem
-------
Opening ui/studio.html via file:// protocol and calling the API at
http://localhost:8001 fails with:
"Access to fetch at '…/release_task' from origin 'null' has been
blocked by CORS policy: Response to preflight request doesn't pass
access control check"
The browser sends a preflight OPTIONS request for the cross-origin
POST, but neither the standalone FastAPI server (api_server.py) nor the
Gradio-mounted API routes (api_routes.py) return the required
Access-Control-Allow-Origin header.
Changes
-------
1. acestep/api_server.py
- Import CORSMiddleware from fastapi.middleware.cors.
- Add CORSMiddleware to the standalone FastAPI app immediately after
creation (before the app starts, so add_middleware() works normally).
2. acestep/gradio_ui/api_routes.py
- Import CORSMiddleware from fastapi.middleware.cors.
- Add _CORS_KWARGS dict with the shared CORS configuration.
- Add _add_cors_middleware() for the normal pre-launch path (used by
setup_api_routes_to_app).
- Add _add_cors_middleware_post_launch() that patches the compiled
middleware_stack directly, because Gradio's demo.launch() starts the
Starlette app before setup_api_routes() is called, and Starlette
raises "Cannot add middleware after an application has started" if
add_middleware() is used post-launch.
- Wire both setup functions to their respective CORS helpers.
CORS policy (applied uniformly in both files)
----------------------------------------------
allow_origins : ["null", "http://localhost", "http://127.0.0.1"]
allow_origin_regex : ^https?://(localhost|127\.0\.0\.1)(:\d+)?$
allow_methods : ["GET", "POST", "OPTIONS"]
allow_headers : ["Content-Type", "Authorization"]
allow_credentials : not set (defaults to False)
Benefits
--------
- studio.html (opened via file://, origin "null") can now call the API.
- Any local dev server on localhost or 127.0.0.1 (any port) also works.
- The Gradio + API path no longer crashes on startup.
Risks & mitigations
--------------------
- Origin "null" is allowed. The "null" origin is sent by file:// pages,
sandboxed iframes, and some redirect flows. A malicious local HTML
file could call the API if opened in the same browser. Mitigation:
the API is bound to localhost by default, and API key auth (--api-key)
is available for sensitive deployments.
- If the server is exposed to the network (0.0.0.0 or --share), only
localhost origins are allowed — external sites cannot call the API.
However, the "null" origin exception still applies to any file://
page on the user's machine.
- The post-launch middleware patching (_add_cors_middleware_post_launch)
accesses app.middleware_stack directly, which is a Starlette internal.
This could break if Starlette refactors its middleware compilation.
Mitigation: guarded by an `if app.middleware_stack is not None` check
and falls back to the normal add_middleware path otherwise.
- allow_credentials is intentionally omitted (False). studio.html uses
plain JSON fetch without cookies. If cookie-based auth is added later,
this will need revisiting.
Co-authored-by: Cursor <cursoragent@cursor.com>
📝 WalkthroughWalkthroughThe changes enable CORS (Cross-Origin Resource Sharing) support for the FastAPI application across two modules. CORSMiddleware is integrated into both the main API server and the Gradio UI API routes, allowing browser-based frontends to access the API from localhost and file:// origins. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@acestep/gradio_ui/api_routes.py`:
- Around line 533-545: In _add_cors_middleware_post_launch, fix the
typographical dash in the inline comment "App hasn't built its stack yet – safe
to use the normal path" by replacing the EN DASH (U+2013) with a standard
hyphen-minus (U+002D) so it reads "App hasn't built its stack yet - safe to use
the normal path"; update the comment in that function accordingly.
🧹 Nitpick comments (1)
acestep/gradio_ui/api_routes.py (1)
516-525: Consider extracting shared CORS configuration.The
_CORS_KWARGSconfiguration is duplicated betweenapi_server.pyand this file. While acceptable for module independence, consider extracting to a shared constants module if these need to stay in sync.
| def _add_cors_middleware_post_launch(app): | ||
| """Wrap an already-started app's middleware stack with CORS. | ||
|
|
||
| ``add_middleware`` raises after Starlette has started, so we patch the | ||
| compiled middleware stack directly instead. | ||
| """ | ||
| from starlette.middleware.cors import CORSMiddleware as _CORSImpl | ||
|
|
||
| if app.middleware_stack is not None: | ||
| app.middleware_stack = _CORSImpl(app=app.middleware_stack, **_CORS_KWARGS) | ||
| else: | ||
| # App hasn't built its stack yet – safe to use the normal path | ||
| _add_cors_middleware(app) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Post-launch middleware patching approach is reasonable given constraints.
Wrapping app.middleware_stack directly is a pragmatic workaround for Gradio's post-launch app access pattern. The fallback to the normal path when the stack isn't built yet is a good safeguard.
One minor fix—line 544 contains an EN DASH (–) instead of a hyphen (-):
📝 Fix typographical character
- # App hasn't built its stack yet – safe to use the normal path
+ # App hasn't built its stack yet - safe to use the normal path📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def _add_cors_middleware_post_launch(app): | |
| """Wrap an already-started app's middleware stack with CORS. | |
| ``add_middleware`` raises after Starlette has started, so we patch the | |
| compiled middleware stack directly instead. | |
| """ | |
| from starlette.middleware.cors import CORSMiddleware as _CORSImpl | |
| if app.middleware_stack is not None: | |
| app.middleware_stack = _CORSImpl(app=app.middleware_stack, **_CORS_KWARGS) | |
| else: | |
| # App hasn't built its stack yet – safe to use the normal path | |
| _add_cors_middleware(app) | |
| def _add_cors_middleware_post_launch(app): | |
| """Wrap an already-started app's middleware stack with CORS. | |
| ``add_middleware`` raises after Starlette has started, so we patch the | |
| compiled middleware stack directly instead. | |
| """ | |
| from starlette.middleware.cors import CORSMiddleware as _CORSImpl | |
| if app.middleware_stack is not None: | |
| app.middleware_stack = _CORSImpl(app=app.middleware_stack, **_CORS_KWARGS) | |
| else: | |
| # App hasn't built its stack yet - safe to use the normal path | |
| _add_cors_middleware(app) |
🧰 Tools
🪛 Ruff (0.14.14)
[warning] 544-544: Comment contains ambiguous – (EN DASH). Did you mean - (HYPHEN-MINUS)?
(RUF003)
🤖 Prompt for AI Agents
In `@acestep/gradio_ui/api_routes.py` around lines 533 - 545, In
_add_cors_middleware_post_launch, fix the typographical dash in the inline
comment "App hasn't built its stack yet – safe to use the normal path" by
replacing the EN DASH (U+2013) with a standard hyphen-minus (U+002D) so it reads
"App hasn't built its stack yet - safe to use the normal path"; update the
comment in that function accordingly.
|
@ChuxiJ I took a look into the ui and the api folder and found the original simple html won't be working by "click to open" mechanism. the API backend was not setup CORS for good, this temporally fix is allowing direct html file open to access the API features, more safer approach is to let user (your IDE might have build in web server for you to "click to open" the HTML file directly? I used to use Intelij IDEA I know they does like that) |
|
We don’t need to develop or design this part for now. By then, we’ll support more features to better cover workflows like Cover, Remix, and Edit, along with project refactoring and more complete tutorials. |
Problem
Opening ui/studio.html via file:// protocol and calling the API at http://localhost:8001 fails with:
"Access to fetch at '…/release_task' from origin 'null' has been
blocked by CORS policy: Response to preflight request doesn't pass
access control check"
The browser sends a preflight OPTIONS request for the cross-origin POST, but neither the standalone FastAPI server (api_server.py) nor the Gradio-mounted API routes (api_routes.py) return the required Access-Control-Allow-Origin header.
Changes
acestep/api_server.py
acestep/gradio_ui/api_routes.py
CORS policy (applied uniformly in both files)
allow_origins : ["null", "http://localhost", "http://127.0.0.1"]
allow_origin_regex : ^https?://(localhost|127.0.0.1)(:\d+)?$
allow_methods : ["GET", "POST", "OPTIONS"]
allow_headers : ["Content-Type", "Authorization"]
allow_credentials : not set (defaults to False)
Benefits
Risks & mitigations
if app.middleware_stack is not Nonecheck and falls back to the normal add_middleware path otherwise.Summary by CodeRabbit