aiohttp-cors
aiohttp-cors copied to clipboard
Problems with aiohttp 3.0.1
This code works fine with aiohttp 2.3.10:
def setup_routes(app):
app.router.add_routes(routes)
setup_swagger(app,
api_base_url='/',
swagger_url='/api/doc',
description='API testing interface',
title='API',
api_version='2.0.0')
cors = aiohttp_cors.setup(app, defaults={
"*": aiohttp_cors.ResourceOptions(
allow_credentials=True,
expose_headers="*",
allow_headers="*",
)
})
for route in list(app.router.routes()):
if not isinstance(route.resource, StaticResource): # <<< WORKAROUND
cors.add(route)
curl -H "Origin: http://example.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: X-Requested-With" -X OPTIONS --verbose localhost:8080/api/users
* Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> OPTIONS /api/users HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: http://example.com
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: POST
< Access-Control-Allow-Headers: X-REQUESTED-WITH
< Content-Length: 0
< Content-Type: application/octet-stream
< Date: Wed, 14 Feb 2018 23:19:55 GMT
< Server: Python/3.6 aiohttp/2.3.10
<
But following (fixed OPTIONS error, adding routes differently) code fails for aiohttp 3.0.1:
# This code fails with:
# RuntimeError: Added route will never be executed, method OPTIONS is already registered
# for route in list(app.router.routes()):
# if not isinstance(route.resource, StaticResource): # <<< WORKAROUND
# cors.add(route)
for resource in app.router.resources():
cors.add(resource)
Same cURL request results in:
* Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> OPTIONS /api/users HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
>
< HTTP/1.1 403 Forbidden
< Content-Type: text/plain; charset=utf-8
< Content-Length: 99
< Date: Wed, 14 Feb 2018 23:21:01 GMT
< Server: Python/3.6 aiohttp/3.0.1
<
* Connection #0 to host localhost left intact
CORS preflight request failed: request method 'POST' is not allowed for 'http://example.com' origin
Actually with the following code CORS doesn't work even for 2.3.10:
for resource in app.router.resources():
cors.add(resource)
Route definition:
@routes.post('/api/users')
async def create_user(request: Request):
return web.json_response(status=web.HTTPCreated.status_code)
We have the issue here, have you found a workaround?
Guys, the library has several technical debts.
I've converted all tests to pytest fixtures usage and replaced yield from
with async/await
syntax.
Next thing is getting rid of special flag for aiohttp.web.View
support in favor of isinstance
check.
After getting this done the code will be ready to adopting to aiohttp 3.
I expect to find a time for it in a week.
Ok thanks for your answer!
Fixed by #160
I hate to be that guy, but will there be a new release to PyPI? I see there was a commit to bump the version, but I don't see it published yet. Thanks :)
Thanks for remember. Yesterday travis was overwhelmed, I forgot to initiate a new release building procedure. Done
Having following error:
CORS preflight request failed: request method 'POST' is not allowed for 'http://example.com' origin
with: aiohttp==3.0.9 aiohttp-cors==0.7.0
same code works for aiohttp 2 and aiohttp-cors 0.6.0. Is there real example of adding routes to cors that do work and was tested?
https://github.com/aio-libs/aiohttp-cors/blob/master/aiohttp_cors/urldispatcher_router_adapter.py#L296
Here resource_config.method_config
is an empty dict. So if not setting default allow_methods to '*' globally - requests do not work with CORS
btw. Adding to cors with both methods doesn't help:
for resource in app.router.resources():
cors.add(resource)
for route in list(app.router.routes()):
if not isinstance(route.resource, StaticResource): # <<< WORKAROUND
cors.add(route)
The same for me. Rolled back to aiohttp 2 and aiohttp_cors 0.6.0
Same here. aiohttp 2.0 + aiohttp-cors 0.6.0 seems to be a good solution for now.
Guys, if somebody wants to provide a PR -- you are welcome. I'm convinced that the problem exists but have no estimation for the fix.
@asvetlov I'll try to look into it over the weekend. Btw, for me, this only happens on localhost, all other places work fine.
Cool!
I could make some progress to solve this problem. This problem happens when you tried to name all routes as it recommended by Swagger notation. And I do not find any fast solution to fix it. Script to reproduce this problem:
import asyncio
import aiohttp
import aiohttp_cors
from aiohttp.web_runner import GracefulExit
async def handler(request):
return aiohttp.web.Response(
text="Hello!",
headers={
"X-Custom-Server-Header": "Custom data",
})
app = aiohttp.web.Application()
cors = aiohttp_cors.setup(app, defaults={
"http://request-from": aiohttp_cors.ResourceOptions(
allow_credentials=True,
expose_headers="*",
allow_headers="*",
),
})
routes = [{
'method': 'GET',
'path': '/test',
'handler': handler,
'name': 'test-good'
}, {
'method': 'POST',
'path': '/test',
'handler': handler,
'name': 'test-good'
}, {
'method': 'GET',
'path': '/test-bad',
'handler': handler,
'name': 'test-bad-get'
}, {
'method': 'POST',
'path': '/test-bad',
'handler': handler,
'name': 'test-bad-post'
}, ]
for route in routes:
cors.add(
app.router.add_route(
method=route['method'],
path=route['path'],
handler=route['handler'],
name=route['name']
)
)
loop = asyncio.get_event_loop()
handler = app._make_handler()
server = loop.run_until_complete(
loop.create_server(
handler,
host='localhost',
port='8081'
)
)
try:
loop.run_forever()
except (GracefulExit, KeyboardInterrupt):
pass
finally:
loop.stop()
GET
and POST
for /test
works perfect.
GET
and POST
for /test-bad
isn't work as expected.
For self._resource_config
at https://github.com/aio-libs/aiohttp-cors/blob/6efa4b5ed41bd8ae272b092d90c6302fd65b78c7/aiohttp_cors/urldispatcher_router_adapter.py#L281
we will get some thing like that:
{
<PlainResource 'test-bad-get' /test-bad>: instance(_ResourceConfig):
default_config: {
},
method_config: {
'GET': {
},
}
<PlainResource 'test-bad-post' /test-bad>: instance(_ResourceConfig):
default_config: {
},
method_config: {
'POST': {
},
}
<PlainResource 'test-good' /test>: instance(_ResourceConfig):
default_config: {
},
method_config: {
'GET': {
},
'POST': {
},
}
}
But for OPTION request to url /test-bad resource
nether with Access-Control-Request-Method
set to 'GET' or 'POST' at
https://github.com/aio-libs/aiohttp-cors/blob/6efa4b5ed41bd8ae272b092d90c6302fd65b78c7/aiohttp_cors/urldispatcher_router_adapter.py#L280
will return every time:
<PlainResource 'test-bad-get' /test-bad>
So we try to find method POST
in <PlainResource 'test-bad-get' /test-bad>
node of self._resource_config
and couldn't as it designed.
That's interesting.
Technically test-bad-get
and test-bad-post
are the same resource which always returns the same URL in url_for()
.
Perhaps aiohttp should raise a warning on trying to add the same URL pattern under different names.
Would be nice to fix aiohttp-cors
to correctly process this case as well maybe but I not sure how complex the fix is.
I have this problem also. I'm keeping with aiohttp 2.3.10. Thanks.
aiohttp-3.3.2 + aiohttp-cors-0.7.0 works fine too! <3
Hey guys ! I think i have the same issue. @valentinmk did you find a workaround ?
@TTRh I used the above mentioned versions and it worked. Unfortunately I was not able to make it work with the latest version.
That sucks... :/
Hum only rollbacking to aiohttp 2 worked for me :/
def setup_routes(app): app.router.add_routes(routes) setup_swagger(app, api_base_url='/', swagger_url='/api/doc', description='API testing interface', title='API', api_version='2.0.0') cors = aiohttp_cors.setup(app, defaults={ "*": aiohttp_cors.ResourceOptions( allow_credentials=True, expose_headers="*", allow_headers="*", ) }) for route in list(app.router.routes()): if not isinstance(route.resource, StaticResource): # <<< WORKAROUND cors.add(route)
This code worked for me with aiohttp 3.5.4, aiohttp-cors 0.7.0
up) same problems with aiohttp 3.6.2 and aiohttp-cors 0.7.0
Pull Request for aiohttp-cors is welcome!
I'm faced with this issue with POST requests and CORS also, but everything works fine with this code:
from aiohttp_cors import setup as cors_setup, ResourceOptions
...
routes = [
web.get("/", handle),
web.post("/something", another_handle),
]
app.router.add_routes(routes)
cors = cors_setup(
app,
defaults={
"*": ResourceOptions(
allow_credentials=True, expose_headers="*", allow_headers="*",
)
},
)
for route in list(app.router.routes()):
cors.add(route)
Versions: aiohttp
3.6.2 and aiohttp-cors
0.7.0
Maybe this will help someone else with this issue.
from aiohttp_cors import setup as cors_setup, ResourceOptions
thanks it's work for me