Skip to content
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

CORS instructions incorrect for Sanic #2998

Open
1 task done
toddwildey opened this issue Sep 16, 2024 · 0 comments
Open
1 task done

CORS instructions incorrect for Sanic #2998

toddwildey opened this issue Sep 16, 2024 · 0 comments
Labels

Comments

@toddwildey
Copy link

toddwildey commented Sep 16, 2024

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I have found the instructions for configuring CORS listed here to be incorrect: https://sanic.dev/en/guide/how-to/cors.html

When following these instructions, I would run into errors like the following:

Main  2024-09-16 00:32:51 -0400 ERROR:    Exception occurred while handling uri: 'http://localhost:8080/api/sessions/54b75e23-7ef4-4de1-9953-b562437080ee'
Traceback (most recent call last):
  File "handle_request", line 75, in handle_request
    from sanic.logging.setup import setup_logging
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               AttributeError: 'types.SimpleNamespace' object has no attribute 'request_middleware'
self.route
<Route: name=REDACTED.wrapped_handler path=api/sessions/<session_id:str>>
self.route.extra
namespace(ident='REDACTED.wrapped_handler', ignore_body=False, stream=False, hosts=[None], static=False, error_format='', websocket=False)
Main  2024-09-16 00:32:51 -0400 ERROR:    Exception occurred in one of response middleware handlers
Traceback (most recent call last):
  File "handle_request", line 75, in handle_request
    from sanic.logging.setup import setup_logging
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               AttributeError: 'types.SimpleNamespace' object has no attribute 'request_middleware'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/Volumes/workspace/Projects/ontology/oracle/automaton/.venv/lib/python3.11/site-packages/sanic/request/types.py", line 405, in respond
    self.route and self.route.extra and self.route.extra.response_middleware
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                        AttributeError: 'types.SimpleNamespace' object has no attribute 'response_middleware' 

Specifically, I found that removing the app.router.reset() and app.router.finalize() from options.py fixed this issue:

def setup_options(app: Sanic, _):
    # app.router.reset()
    needs_options = _compile_routes_needing_options(app.router.routes_all)
    for uri, methods in needs_options.items():
        app.add_route(
            _options_wrapper(options_handler, methods),
            uri,
            methods=["OPTIONS"],
        )
    # app.router.finalize()

I'm not sure how critical it is for these to be invoked, but it seems everything is working fine without them.

Additionally, I was able to reduce the cors.py and options.py to the following, which are working:

cors.py

from sanic import Request, HTTPResponse

from typing import Iterable

def _add_cors_headers(request: Request, response: HTTPResponse, methods: str) -> None:
    response.headers['Access-Control-Allow-Headers'] = "origin, content-type, accept, authorization, x-xsrf-token, x-request-id"
    response.headers['Access-Control-Allow-Methods'] = methods
    response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin') or '*'

def add_cors_headers(request: Request, response: HTTPResponse):
    _add_cors_headers(request, response, request.app.ctx.uri_methods_mapping[request.route.uri])

options.py

from collections import defaultdict
from typing import Dict

from sanic import empty, Request, HTTPResponse, Sanic
from sanic.router import Route

from .cors import _add_cors_headers

def _compile_routes_needing_options(routes: Dict[str, Route]) -> Dict[str, str]:
    needs_options = defaultdict(list)
    # This is 21.12 and later. You will need to change this for older versions.
    for route in routes:
        if "OPTIONS" not in route.methods:
            needs_options[route.uri].extend(route.methods)

    return {
        uri: ",".join(methods) for uri, methods in dict(needs_options).items()
    }

async def options_handler(request: Request, *args, **kwargs) -> HTTPResponse:
    return empty()

def setup_options(app: Sanic, _):
    uri_methods_mapping = _compile_routes_needing_options(app.router.routes)
    app.ctx.uri_methods_mapping = uri_methods_mapping

    for uri, methods in uri_methods_mapping.items():
        app.add_route(options_handler, uri, methods = ["OPTIONS"])

I understand this may not suite everyone's needs - especially if folks need custom OPTIONS endpoints that have more specific logic. Nonetheless, I figured I would share my working configuration.

The following is the requirements.txt for this project:

aiofiles==24.1.0
annotated-types==0.7.0
anyio==4.4.0
appdirs==1.4.4
distro==1.9.0
fs==2.4.16
groq==0.9.0
h11==0.14.0
html5tagger==1.3.0
httpcore==1.0.5
httptools==0.6.1
httpx==0.27.0
multidict==6.0.5
openai==1.35.13
pydantic-core==2.20.1
pydantic==2.8.2
pygments==2.18.0
pystache==0.6.5
sanic-routing==23.12.0
sanic==24.6.0
setuptools==73.0.1
sniffio==1.3.1
tracerite==1.1.1
ujson==5.10.0
uvloop==0.20.0
websockets==13.0

The following is the requirements-dev.txt for this project:

build~=1.2.1
coverage~=7.5.3
pytest~=8.2.1
tox~=4.15.0

Code snippet

No response

Expected Behavior

No response

How do you run Sanic?

As a script (app.run or Sanic.serve)

Operating System

Linux

Sanic Version

24.6.0

Additional context

No response

@toddwildey toddwildey added the bug label Sep 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant