Package: aiohttp_cors
CORS support for aiohttpaiohttp_corslibrary implementsCross Origin Resource Sharing (CORS)support foraiohttpasyncio-powered asynchronous HTTP server.Jump directly toUsagepart to see how to useaiohttp_cors.Same-origin policyWeb security model is tightly connected toSame-origin policy (SOP).
In short: web pages cannotReadresources which origin
doesn’t match origin of requested page, but canEmbed(orExecute)
resources and have limited ability toWriteresources.Origin of a page is defined in theStandardas tuple(schema, host, port)(there is a notable exception with Internet Explorer: it doesn’t use port to
define origin, but uses it’s ownSecurity Zones).CanEmbedmeans that resource from other origin can be embedded into
the page,
e.g. by using<scriptsrc="...">,<imgsrc="...">,<iframesrc="...">.CannotReadmeans that resource from other originsourcecannot be
obtained by page
(source— any information that would allow to reconstruct resource).
E.g. the page canEmbedimage with<imgsrc="...">,
but it can’t get information about specific pixels, so page can’t reconstruct
original image
(though some information from the other resource may still be leaked:
e.g. the page can read embedded image dimensions).Limited ability toWritemeans, that the page can send POST requests to
other origin with limited set ofContent-Typevalues and headers.Restriction toReadresource from other origin is related to authentication
mechanism that is used by browsers:
when browser reads (downloads) resource he automatically sends all security
credentials that user previously authorized for that resource
(e.g. cookies, HTTP Basic Authentication).For example, ifReadwould be allowed and user is authenticated
in some internet banking,
malicious page would be able to embed internet banking page withiframe(since authentication is done by the browser it may be embedded as if
user is directly navigated to internet banking page),
then read user private information by readingsourceof the embedded page
(which may be not only source code, but, for example,
screenshot of the embedded internet banking page).Cross-origin resource sharingCross-origin Resource Sharing (CORS)allows to override
SOP for specific resources.In short, CORS works in the following way.When pagehttps://client.example.comrequest (Read) resourcehttps://server.example.com/resourcethat have other origin,
browser implicitly appendsOrigin:https://client.example.comheader
to the HTTP request,
effectively requesting server to give read permission for
the resource to thehttps://client.example.compage:GET /resource HTTP/1.1
Origin: https://client.example.com
Host: server.example.comIf server allows access from the page to the resource, it responds with
resource withAccess-Control-Allow-Origin:https://client.example.comHTTP header
(optionally allowing exposing custom server headers to the page and
enabling use of the user credentials on the server resource):Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Server-HeaderBrowser checks, if server responded with properAccess-Control-Allow-Originheader and accordingly allows or denies
access for the obtained resource to the page.CORS specification designed in a way that servers that are not aware
of CORS will not expose any additional information, except allowed by the
SOP.To request resources with custom headers or using custom HTTP methods
(e.g.PUT,DELETE) that are not allowed by SOP,
CORS-enabled browser first sendpreflight requestto the
resource usingOPTIONSmethod, in which he queries access to the resource
with specific method and headers:OPTIONS / HTTP/1.1
Origin: https://client.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Client-HeaderCORS-enabled server responds is requested method is allowed and which of
the specified headers are allowed:Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: X-Client-Header
Access-Control-Max-Age: 3600Browser checks response to preflight request, and, if actual request allowed,
does actual request.InstallationYou can installaiohttp_corsas a typical Python library from PyPI or
from git:$pipinstallaiohttp_corsNote thataiohttp_corsrequires versions of Python >= 3.4.1 andaiohttp>= 1.1.UsageTo useaiohttp_corsyou need to configure the application and
enable CORS onresources and routesthat you want to expose:importasynciofromaiohttpimportwebimportaiohttp_cors@asyncio.coroutinedefhandler(request):returnweb.Response(text="Hello!",headers={"X-Custom-Server-Header":"Custom data",})app=web.Application()# `aiohttp_cors.setup` returns `aiohttp_cors.CorsConfig` instance.# The `cors` instance will store CORS configuration for the# application.cors=aiohttp_cors.setup(app)# To enable CORS processing for specific route you need to add# that route to the CORS configuration object and specify its# CORS options.resource=cors.add(app.router.add_resource("/hello"))route=cors.add(resource.add_route("GET",handler),{"http://client.example.org":aiohttp_cors.ResourceOptions(allow_credentials=True,expose_headers=("X-Custom-Server-Header",),allow_headers=("X-Requested-With","Content-Type"),max_age=3600,)})Each route has it’s own CORS configuration passed inCorsConfig.add()method.CORS configuration is a mapping from origins to options for that origins.In the example above CORS is configured for the resource under path/helloand HTTP methodGET, and in the context of CORS:This resource will be available using CORS only tohttp://client.example.orgorigin.Passing of credentials to this resource will be allowed.The resource will expose to the clientX-Custom-Server-Headerserver header.The client will be allowed to passX-Requested-WithandContent-Typeheaders to the server.Preflight requests will be allowed to be cached by client for3600seconds.Resource will be available only to the explicitly specified origins.
You can specify “all other origins” using special*origin:cors.add(route,{"*":aiohttp_cors.ResourceOptions(allow_credentials=False),"http://client.example.org":aiohttp_cors.ResourceOptions(allow_credentials=True),})Here the resource specified byroutewill be available to all origins with
disallowed credentials passing, and with allowed credentials passing only tohttp://client.example.org.By defaultResourceOptionswill be constructed without any allowed CORS
options.
This means, that resource will be available using CORS to specified origin,
but client will not be allowed to send either credentials,
or send non-simple headers, or read from server non-simple headers.To enable sending or receiving all headers you can specify special value*instead of sequence of headers:cors.add(route,{"http://client.example.org":aiohttp_cors.ResourceOptions(expose_headers="*",allow_headers="*"),})You can specify default CORS-enabled resource options usingaiohttp_cors.setup()’sdefaultsargument:cors=aiohttp_cors.setup(app,defaults={# Allow all to read all CORS-enabled resources from# http://client.example.org."http://client.example.org":aiohttp_cors.ResourceOptions(),})# Enable CORS on routes.# According to defaults POST and PUT will be available only to# "http://client.example.org".hello_resource=cors.add(app.router.add_resource("/hello"))cors.add(hello_resource.add_route("POST",handler_post))cors.add(hello_resource.add_route("PUT",handler_put))# In addition to "http://client.example.org", GET request will be# allowed from "http://other-client.example.org" origin.cors.add(hello_resource.add_route("GET",handler),{"http://other-client.example.org":aiohttp_cors.ResourceOptions(),})# CORS will be enabled only on the resources added to `CorsConfig`,# so following resource will be NOT CORS-enabled.app.router.add_route("GET","/private",handler)Also you can specify default options for resources:# Allow POST and PUT requests from "http://client.example.org" origin.hello_resource=cors.add(app.router.add_resource("/hello"),{"http://client.example.org":aiohttp_cors.ResourceOptions(),})cors.add(hello_resource.add_route("POST",handler_post))cors.add(hello_resource.add_route("PUT",handler_put))Resource CORS configuration allows to useallow_methodsoption that
explicitly specifies list of allowed HTTP methods for origin
(or*for all HTTP methods).
By using this option it is not required to add all resource routes to
CORS configuration object:# Allow POST and PUT requests from "http://client.example.org" origin.hello_resource=cors.add(app.router.add_resource("/hello"),{"http://client.example.org":aiohttp_cors.ResourceOptions(allow_methods=["POST","PUT"]),})# No need to add POST and PUT routes into CORS configuration object.hello_resource.add_route("POST",handler_post)hello_resource.add_route("PUT",handler_put)# Still you can add additional methods to CORS configuration object:cors.add(hello_resource.add_route("DELETE",handler_delete))Here is an example of how to enable CORS for all origins with all CORS
features:cors=aiohttp_cors.setup(app,defaults={"*":aiohttp_cors.ResourceOptions(allow_credentials=True,expose_headers="*",allow_headers="*",)})# Add all resources to `CorsConfig`.resource=cors.add(app.router.add_resource("/hello"))cors.add(resource.add_route("GET",handler_get))cors.add(resource.add_route("PUT",handler_put))cors.add(resource.add_route("POST",handler_put))cors.add(resource.add_route("DELETE",handler_delete))Old routes API is supported — you can userouter.add_routerandrouter.register_routeas before, though this usage is discouraged:cors.add(app.router.add_route("GET","/hello",handler),{"http://client.example.org":aiohttp_cors.ResourceOptions(allow_credentials=True,expose_headers=("X-Custom-Server-Header",),allow_headers=("X-Requested-With","Content-Type"),max_age=3600,)})You can enable CORS for all added routes by accessing routes list
in the router:# Setup application routes.app.router.add_route("GET","/hello",handler_get)app.router.add_route("PUT","/hello",handler_put)app.router.add_route("POST","/hello",handler_put)app.router.add_route("DELETE","/hello",handler_delete)# Configure default CORS settings.cors=aiohttp_cors.setup(app,defaults={"*":aiohttp_cors.ResourceOptions(allow_credentials=True,expose_headers="*",allow_headers="*",)})# Configure CORS on all routes.forrouteinlist(app.router.routes()):cors.add(route)You can also useCorsViewMixinonweb.View:classCorsView(web.View,CorsViewMixin):cors_config={"*":ResourceOption(allow_credentials=True,allow_headers="X-Request-ID",)}@asyncio.coroutinedefget(self):returnweb.Response(text="Done")@custom_cors({"*":ResourceOption(allow_credentials=True,allow_headers="*",)})@asyncio.coroutinedefpost(self):returnweb.Response(text="Done")cors=aiohttp_cors.setup(app,defaults={"*":aiohttp_cors.ResourceOptions(allow_credentials=True,expose_headers="*",allow_headers="*",)})cors.add(app.router.add_route("*","/resource",CorsView),webview=True)SecurityTODO: fill thisDevelopmentTo setup development environment:# Clone sources repository:gitclonehttps://github.com/aio-libs/aiohttp_cors.git.# Create and activate virtual Python environment:python3-mvenvenvsourceenv/bin/activate# Install requirements and aiohttp_cors into virtual environmentpipinstall-rrequirements-dev.txtTo run tests:toxTo run only runtime tests in current environment:py.testTo run only static code analysis checks:tox-echeckRunning Selenium testsTo run Selenium tests with Firefox web driver you need to install Firefox.To run Selenium tests with Chromium web driver you need to:Install Chrome driver. On Ubuntu 14.04 it’s inchromium-chromedriverpackage.Either addchromedriverto PATH or setWEBDRIVER_CHROMEDRIVER_PATHenvironment variable tochromedriver, e.g. on Ubuntu 14.04WEBDRIVER_CHROMEDRIVER_PATH=/usr/lib/chromium-browser/chromedriver.Release processTo release versionvA.B.Cfrom the current version ofmasterbranch
you need to:Create local branchvA.B.C.InCHANGES.rstset release date to today.Inaiohttp_cors/__about__.pychange version fromA.B.Ca0toA.B.C.Create pull request withvA.B.Cbranch, wait for all checks to
successfully finish (Travis and Appveyor).Merge pull request to master.Update and checkoutmasterbranch.Create and push tag for release version to GitHub:gittagvA.B.Cgitpush--tagsNow Travis should ran tests again, and build and deploy wheel on PyPI.If Travis release doesn’t work for some reason, use following steps
for manual release upload.Install fresh versions of setuptools and pip.
Installwheelfor building wheels.
Installtwinefor uploading to PyPI.pipinstall-UpipsetuptoolstwinewheelConfigure PyPI credentials in~/.pypirc.Build distribution:rm-rfbuilddist;pythonsetup.pysdistbdist_wheelUpload new release to PyPI:twineuploaddist/*Edit release description on GitHub if needed.Announce new release on theaio-libsmailing list:https://groups.google.com/forum/#!forum/aio-libs.Post release steps:InCHANGES.rstadd template for the next release.Inaiohttp_cors/__about__.pychange version fromA.B.CtoA.(B+1).0a0.BugsPlease report bugs, issues, feature requests, etc. onGitHub.LicenseCopyright 2015 Vladimir Rutsky <vladimir@rutsky.org>.Licensed under theApache License, Version 2.0,
seeLICENSEfile for details.CHANGES0.7.0 (2018-03-05)Make web view check implicit and type based (#159)Disable Python 3.4 support (#156)Support aiohttp 3.0+ (#155)0.6.0 (2017-12-21)Support aiohttp views byCorsViewMixin(#145)0.5.3 (2017-04-21)Fixtypingbeing installed on Python 3.6.0.5.2 (2017-03-28)Fix tests compatibility withaiohttp2.0.
This release and release v0.5.0 should work onaiohttp2.0.0.5.1 (2017-03-23)Enforceaiohttpversion to be less than 2.0.
Neweraiohttpreleases will be supported in the next release.0.5.0 (2016-11-18)Fix compatibility withaiohttp1.10.4.0 (2016-04-04)Fixed support with new Resources objects introduced inaiohttp0.21.0.
Minimum supported version ofaiohttpis 0.21.4 now.New Resources objects are supported.
You can specify default configuration for a Resource and useallow_methodsto explicitly list allowed methods (or*for all
HTTP methods):# Allow POST and PUT requests from "http://client.example.org" origin.hello_resource=cors.add(app.router.add_resource("/hello"),{"http://client.example.org":aiohttp_cors.ResourceOptions(allow_methods=["POST","PUT"]),})# No need to add POST and PUT routes into CORS configuration object.hello_resource.add_route("POST",handler_post)hello_resource.add_route("PUT",handler_put)# Still you can add additional methods to CORS configuration object:cors.add(hello_resource.add_route("DELETE",handler_delete))AbstractRouterAdapterwas completely rewritten to be more Router
agnostic.0.3.0 (2016-02-06)RenameUrlDistatcherRouterAdaptertoUrlDispatcherRouterAdapter.Set maximum supportedaiohttpversion to0.20.2, see bug #30 for
details.0.2.0 (2015-11-30)Move ABCs fromaiohttp_cors.router_adaptertoaiohttp_cors.abc.RenameRouterAdaptertoAbstractRouterAdapter.Fix bug with configuring CORS for named routes.0.1.0 (2015-11-05)Initial release.