Enable CORS

This commit is contained in:
Senad Uka
2019-11-17 16:29:42 +01:00
parent a7f360de82
commit 6c121187cf
17 changed files with 927 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
Copyright (C) 2016 Cory Dolphin, Olin College
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,162 @@
Metadata-Version: 2.1
Name: Flask-Cors
Version: 3.0.8
Summary: A Flask extension adding a decorator for CORS support
Home-page: https://github.com/corydolphin/flask-cors
Author: Cory Dolphin
Author-email: corydolphin@gmail.com
License: MIT
Platform: any
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Dist: Flask (>=0.9)
Requires-Dist: Six
Flask-CORS
==========
|Build Status| |Latest Version| |Supported Python versions|
|License|
A Flask extension for handling Cross Origin Resource Sharing (CORS),
making cross-origin AJAX possible.
This package has a simple philosophy, when you want to enable CORS, you
wish to enable it for all use cases on a domain. This means no mucking
around with different allowed headers, methods, etc. By default,
submission of cookies across domains is disabled due to the security
implications, please see the documentation for how to enable
credential'ed requests, and please make sure you add some sort of
`CSRF <http://en.wikipedia.org/wiki/Cross-site_request_forgery>`__
protection before doing so!
Installation
------------
Install the extension with using pip, or easy\_install.
.. code:: bash
$ pip install -U flask-cors
Usage
-----
This package exposes a Flask extension which by default enables CORS support on all routes, for all origins and methods. It allows parameterization of all CORS headers on a per-resource level. The package also contains a decorator, for those who prefer this approach.
Simple Usage
~~~~~~~~~~~~
In the simplest case, initialize the Flask-Cors extension with default
arguments in order to allow CORS for all domains on all routes. See the
full list of options in the `documentation <https://flask-cors.corydolphin.com/en/latest/api.html#extension>`__.
.. code:: python
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"
Resource specific CORS
^^^^^^^^^^^^^^^^^^^^^^
Alternatively, you can specify CORS options on a resource and origin
level of granularity by passing a dictionary as the `resources` option,
mapping paths to a set of options. See the
full list of options in the `documentation <https://flask-cors.corydolphin.com/en/latest/api.html#extension>`__.
.. code:: python
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
@app.route("/api/v1/users")
def list_users():
return "user example"
Route specific CORS via decorator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This extension also exposes a simple decorator to decorate flask routes
with. Simply add ``@cross_origin()`` below a call to Flask's
``@app.route(..)`` to allow CORS on a given route. See the
full list of options in the `decorator documentation <https://flask-cors.corydolphin.com/en/latest/api.html#decorator>`__.
.. code:: python
@app.route("/")
@cross_origin()
def helloWorld():
return "Hello, cross-origin-world!"
Documentation
-------------
For a full list of options, please see the full
`documentation <https://flask-cors.corydolphin.com/en/latest/api.html>`__
Troubleshooting
---------------
If things aren't working as you expect, enable logging to help understand
what is going on under the hood, and why.
.. code:: python
logging.getLogger('flask_cors').level = logging.DEBUG
Tests
-----
A simple set of tests is included in ``test/``. To run, install nose,
and simply invoke ``nosetests`` or ``python setup.py test`` to exercise
the tests.
Contributing
------------
Questions, comments or improvements? Please create an issue on
`Github <https://github.com/corydolphin/flask-cors>`__, tweet at
`@corydolphin <https://twitter.com/corydolphin>`__ or send me an email.
I do my best to include every contribution proposed in any way that I
can.
Credits
-------
This Flask extension is based upon the `Decorator for the HTTP Access
Control <http://flask.pocoo.org/snippets/56/>`__ written by Armin
Ronacher.
.. |Build Status| image:: https://api.travis-ci.org/corydolphin/flask-cors.svg?branch=master
:target: https://travis-ci.org/corydolphin/flask-cors
.. |Latest Version| image:: https://img.shields.io/pypi/v/Flask-Cors.svg
:target: https://pypi.python.org/pypi/Flask-Cors/
.. |Supported Python versions| image:: https://img.shields.io/pypi/pyversions/Flask-Cors.svg
:target: https://img.shields.io/pypi/pyversions/Flask-Cors.svg
.. |License| image:: http://img.shields.io/:license-mit-blue.svg
:target: https://pypi.python.org/pypi/Flask-Cors/

View File

@@ -0,0 +1,16 @@
Flask_Cors-3.0.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Flask_Cors-3.0.8.dist-info/LICENSE,sha256=bhob3FSDTB4HQMvOXV9vLK4chG_Sp_SCsRZJWU-vvV0,1069
Flask_Cors-3.0.8.dist-info/METADATA,sha256=WAcJQwYw0qqy43tjaa9SBNOYPCyzqayKZZwJ_RLRSi0,5368
Flask_Cors-3.0.8.dist-info/RECORD,,
Flask_Cors-3.0.8.dist-info/WHEEL,sha256=h_aVn5OB2IERUjMbi2pucmR_zzWJtk303YXvhh60NJ8,110
Flask_Cors-3.0.8.dist-info/top_level.txt,sha256=aWye_0QNZPp_QtPF4ZluLHqnyVLT9CPJsfiGhwqkWuo,11
flask_cors/__init__.py,sha256=oJExwfR7yU3HAsmQ_EfL6KoLK3zq3J9HsET9r-56sfM,791
flask_cors/__pycache__/__init__.cpython-37.pyc,,
flask_cors/__pycache__/core.cpython-37.pyc,,
flask_cors/__pycache__/decorator.cpython-37.pyc,,
flask_cors/__pycache__/extension.cpython-37.pyc,,
flask_cors/__pycache__/version.cpython-37.pyc,,
flask_cors/core.py,sha256=ZzJ4yoAhgbt-xVBqFFwsDDCzKbiyKL7PlufoVByq9ro,13895
flask_cors/decorator.py,sha256=iiwjUi0lVeCm4OJJHY5Cvuzj2nENbUns3Iq6zqKXuss,4937
flask_cors/extension.py,sha256=FsHOkMSMj5Zv0u_I0fgVdLh0QDUpmEvt_8Xw0qVBK-8,7427
flask_cors/version.py,sha256=sF9np2e_SuSeS9bX2MWnkn45e-mKQh1f9lVU_kod4Yg,22

View File

@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.4)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
"""
flask_cors
~~~~
Flask-CORS is a simple extension to Flask allowing you to support cross
origin resource sharing (CORS) using a simple decorator.
:copyright: (c) 2016 by Cory Dolphin.
:license: MIT, see LICENSE for more details.
"""
from .decorator import cross_origin
from .extension import CORS
from .version import __version__
__all__ = ['CORS', 'cross_origin']
# Set default logging handler to avoid "No handler found" warnings.
import logging
from logging import NullHandler
# Set initial level to WARN. Users must manually enable logging for
# flask_cors to see our logging.
rootlogger = logging.getLogger(__name__)
rootlogger.addHandler(NullHandler())
if rootlogger.level == logging.NOTSET:
rootlogger.setLevel(logging.WARN)

View File

@@ -0,0 +1,383 @@
# -*- coding: utf-8 -*-
"""
core
~~~~
Core functionality shared between the extension and the decorator.
:copyright: (c) 2016 by Cory Dolphin.
:license: MIT, see LICENSE for more details.
"""
import re
import logging
try:
# on python 3
from collections.abc import Iterable
except ImportError:
# on python 2.7 and pypy
from collections import Iterable
from datetime import timedelta
from six import string_types
from flask import request, current_app
from werkzeug.datastructures import Headers, MultiDict
LOG = logging.getLogger(__name__)
# Response Headers
ACL_ORIGIN = 'Access-Control-Allow-Origin'
ACL_METHODS = 'Access-Control-Allow-Methods'
ACL_ALLOW_HEADERS = 'Access-Control-Allow-Headers'
ACL_EXPOSE_HEADERS = 'Access-Control-Expose-Headers'
ACL_CREDENTIALS = 'Access-Control-Allow-Credentials'
ACL_MAX_AGE = 'Access-Control-Max-Age'
# Request Header
ACL_REQUEST_METHOD = 'Access-Control-Request-Method'
ACL_REQUEST_HEADERS = 'Access-Control-Request-Headers'
ALL_METHODS = ['GET', 'HEAD', 'POST', 'OPTIONS', 'PUT', 'PATCH', 'DELETE']
CONFIG_OPTIONS = ['CORS_ORIGINS', 'CORS_METHODS', 'CORS_ALLOW_HEADERS',
'CORS_EXPOSE_HEADERS', 'CORS_SUPPORTS_CREDENTIALS',
'CORS_MAX_AGE', 'CORS_SEND_WILDCARD',
'CORS_AUTOMATIC_OPTIONS', 'CORS_VARY_HEADER',
'CORS_RESOURCES', 'CORS_INTERCEPT_EXCEPTIONS',
'CORS_ALWAYS_SEND']
# Attribute added to request object by decorator to indicate that CORS
# was evaluated, in case the decorator and extension are both applied
# to a view.
FLASK_CORS_EVALUATED = '_FLASK_CORS_EVALUATED'
# Strange, but this gets the type of a compiled regex, which is otherwise not
# exposed in a public API.
RegexObject = type(re.compile(''))
DEFAULT_OPTIONS = dict(origins='*',
methods=ALL_METHODS,
allow_headers='*',
expose_headers=None,
supports_credentials=False,
max_age=None,
send_wildcard=False,
automatic_options=True,
vary_header=True,
resources=r'/*',
intercept_exceptions=True,
always_send=True)
def parse_resources(resources):
if isinstance(resources, dict):
# To make the API more consistent with the decorator, allow a
# resource of '*', which is not actually a valid regexp.
resources = [(re_fix(k), v) for k, v in resources.items()]
# Sort by regex length to provide consistency of matching and
# to provide a proxy for specificity of match. E.G. longer
# regular expressions are tried first.
def pattern_length(pair):
maybe_regex, _ = pair
return len(get_regexp_pattern(maybe_regex))
return sorted(resources,
key=pattern_length,
reverse=True)
elif isinstance(resources, string_types):
return [(re_fix(resources), {})]
elif isinstance(resources, Iterable):
return [(re_fix(r), {}) for r in resources]
# Type of compiled regex is not part of the public API. Test for this
# at runtime.
elif isinstance(resources, RegexObject):
return [(re_fix(resources), {})]
else:
raise ValueError("Unexpected value for resources argument.")
def get_regexp_pattern(regexp):
"""
Helper that returns regexp pattern from given value.
:param regexp: regular expression to stringify
:type regexp: _sre.SRE_Pattern or str
:returns: string representation of given regexp pattern
:rtype: str
"""
try:
return regexp.pattern
except AttributeError:
return str(regexp)
def get_cors_origins(options, request_origin):
origins = options.get('origins')
wildcard = r'.*' in origins
# If the Origin header is not present terminate this set of steps.
# The request is outside the scope of this specification.-- W3Spec
if request_origin:
LOG.debug("CORS request received with 'Origin' %s", request_origin)
# If the allowed origins is an asterisk or 'wildcard', always match
if wildcard and options.get('send_wildcard'):
LOG.debug("Allowed origins are set to '*'. Sending wildcard CORS header.")
return ['*']
# If the value of the Origin header is a case-sensitive match
# for any of the values in list of origins
elif try_match_any(request_origin, origins):
LOG.debug("The request's Origin header matches. Sending CORS headers.", )
# Add a single Access-Control-Allow-Origin header, with either
# the value of the Origin header or the string "*" as value.
# -- W3Spec
return [request_origin]
else:
LOG.debug("The request's Origin header does not match any of allowed origins.")
return None
elif options.get('always_send'):
if wildcard:
# If wildcard is in the origins, even if 'send_wildcard' is False,
# simply send the wildcard. Unless supports_credentials is True,
# since that is forbidded by the spec..
# It is the most-likely to be correct thing to do (the only other
# option is to return nothing, which almost certainly not what
# the developer wants if the '*' origin was specified.
if options.get('supports_credentials'):
return None
else:
return ['*']
else:
# Return all origins that are not regexes.
return sorted([o for o in origins if not probably_regex(o)])
# Terminate these steps, return the original request untouched.
else:
LOG.debug("The request did not contain an 'Origin' header. This means the browser or client did not request CORS, ensure the Origin Header is set.")
return None
def get_allow_headers(options, acl_request_headers):
if acl_request_headers:
request_headers = [h.strip() for h in acl_request_headers.split(',')]
# any header that matches in the allow_headers
matching_headers = filter(
lambda h: try_match_any(h, options.get('allow_headers')),
request_headers
)
return ', '.join(sorted(matching_headers))
return None
def get_cors_headers(options, request_headers, request_method):
origins_to_set = get_cors_origins(options, request_headers.get('Origin'))
headers = MultiDict()
if not origins_to_set: # CORS is not enabled for this route
return headers
for origin in origins_to_set:
headers.add(ACL_ORIGIN, origin)
headers[ACL_EXPOSE_HEADERS] = options.get('expose_headers')
if options.get('supports_credentials'):
headers[ACL_CREDENTIALS] = 'true' # case sensative
# This is a preflight request
# http://www.w3.org/TR/cors/#resource-preflight-requests
if request_method == 'OPTIONS':
acl_request_method = request_headers.get(ACL_REQUEST_METHOD, '').upper()
# If there is no Access-Control-Request-Method header or if parsing
# failed, do not set any additional headers
if acl_request_method and acl_request_method in options.get('methods'):
# If method is not a case-sensitive match for any of the values in
# list of methods do not set any additional headers and terminate
# this set of steps.
headers[ACL_ALLOW_HEADERS] = get_allow_headers(options, request_headers.get(ACL_REQUEST_HEADERS))
headers[ACL_MAX_AGE] = options.get('max_age')
headers[ACL_METHODS] = options.get('methods')
else:
LOG.info("The request's Access-Control-Request-Method header does not match allowed methods. CORS headers will not be applied.")
# http://www.w3.org/TR/cors/#resource-implementation
if options.get('vary_header'):
# Only set header if the origin returned will vary dynamically,
# i.e. if we are not returning an asterisk, and there are multiple
# origins that can be matched.
if headers[ACL_ORIGIN] == '*':
pass
elif (len(options.get('origins')) > 1 or
len(origins_to_set) > 1 or
any(map(probably_regex, options.get('origins')))):
headers.add('Vary', 'Origin')
return MultiDict((k, v) for k, v in headers.items() if v)
def set_cors_headers(resp, options):
"""
Performs the actual evaluation of Flas-CORS options and actually
modifies the response object.
This function is used both in the decorator and the after_request
callback
"""
# If CORS has already been evaluated via the decorator, skip
if hasattr(resp, FLASK_CORS_EVALUATED):
LOG.debug('CORS have been already evaluated, skipping')
return resp
# Some libraries, like OAuthlib, set resp.headers to non Multidict
# objects (Werkzeug Headers work as well). This is a problem because
# headers allow repeated values.
if (not isinstance(resp.headers, Headers)
and not isinstance(resp.headers, MultiDict)):
resp.headers = MultiDict(resp.headers)
headers_to_set = get_cors_headers(options, request.headers, request.method)
LOG.debug('Settings CORS headers: %s', str(headers_to_set))
for k, v in headers_to_set.items():
resp.headers.add(k, v)
return resp
def probably_regex(maybe_regex):
if isinstance(maybe_regex, RegexObject):
return True
else:
common_regex_chars = ['*', '\\', ']', '?', '$', '^', '[', ']', '(', ')']
# Use common characters used in regular expressions as a proxy
# for if this string is in fact a regex.
return any((c in maybe_regex for c in common_regex_chars))
def re_fix(reg):
"""
Replace the invalid regex r'*' with the valid, wildcard regex r'/.*' to
enable the CORS app extension to have a more user friendly api.
"""
return r'.*' if reg == r'*' else reg
def try_match_any(inst, patterns):
return any(try_match(inst, pattern) for pattern in patterns)
def try_match(request_origin, maybe_regex):
"""Safely attempts to match a pattern or string to a request origin."""
if isinstance(maybe_regex, RegexObject):
return re.match(maybe_regex, request_origin)
elif probably_regex(maybe_regex):
return re.match(maybe_regex, request_origin, flags=re.IGNORECASE)
else:
try:
return request_origin.lower() == maybe_regex.lower()
except AttributeError:
return request_origin == maybe_regex
def get_cors_options(appInstance, *dicts):
"""
Compute CORS options for an application by combining the DEFAULT_OPTIONS,
the app's configuration-specified options and any dictionaries passed. The
last specified option wins.
"""
options = DEFAULT_OPTIONS.copy()
options.update(get_app_kwarg_dict(appInstance))
if dicts:
for d in dicts:
options.update(d)
return serialize_options(options)
def get_app_kwarg_dict(appInstance=None):
"""Returns the dictionary of CORS specific app configurations."""
app = (appInstance or current_app)
# In order to support blueprints which do not have a config attribute
app_config = getattr(app, 'config', {})
return {
k.lower().replace('cors_', ''): app_config.get(k)
for k in CONFIG_OPTIONS
if app_config.get(k) is not None
}
def flexible_str(obj):
"""
A more flexible str function which intelligently handles stringifying
strings, lists and other iterables. The results are lexographically sorted
to ensure generated responses are consistent when iterables such as Set
are used.
"""
if obj is None:
return None
elif(not isinstance(obj, string_types)
and isinstance(obj, Iterable)):
return ', '.join(str(item) for item in sorted(obj))
else:
return str(obj)
def serialize_option(options_dict, key, upper=False):
if key in options_dict:
value = flexible_str(options_dict[key])
options_dict[key] = value.upper() if upper else value
def ensure_iterable(inst):
"""
Wraps scalars or string types as a list, or returns the iterable instance.
"""
if isinstance(inst, string_types):
return [inst]
elif not isinstance(inst, Iterable):
return [inst]
else:
return inst
def sanitize_regex_param(param):
return [re_fix(x) for x in ensure_iterable(param)]
def serialize_options(opts):
"""
A helper method to serialize and processes the options dictionary.
"""
options = (opts or {}).copy()
for key in opts.keys():
if key not in DEFAULT_OPTIONS:
LOG.warning("Unknown option passed to Flask-CORS: %s", key)
# Ensure origins is a list of allowed origins with at least one entry.
options['origins'] = sanitize_regex_param(options.get('origins'))
options['allow_headers'] = sanitize_regex_param(options.get('allow_headers'))
# This is expressly forbidden by the spec. Raise a value error so people
# don't get burned in production.
if r'.*' in options['origins'] and options['supports_credentials'] and options['send_wildcard']:
raise ValueError("Cannot use supports_credentials in conjunction with"
"an origin string of '*'. See: "
"http://www.w3.org/TR/cors/#resource-requests")
serialize_option(options, 'expose_headers')
serialize_option(options, 'methods', upper=True)
if isinstance(options.get('max_age'), timedelta):
options['max_age'] = str(int(options['max_age'].total_seconds()))
return options

View File

@@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
"""
decorator
~~~~
This unit exposes a single decorator which should be used to wrap a
Flask route with. It accepts all parameters and options as
the CORS extension.
:copyright: (c) 2016 by Cory Dolphin.
:license: MIT, see LICENSE for more details.
"""
from functools import update_wrapper
from flask import make_response, request, current_app
from .core import *
LOG = logging.getLogger(__name__)
def cross_origin(*args, **kwargs):
"""
This function is the decorator which is used to wrap a Flask route with.
In the simplest case, simply use the default parameters to allow all
origins in what is the most permissive configuration. If this method
modifies state or performs authentication which may be brute-forced, you
should add some degree of protection, such as Cross Site Forgery
Request protection.
:param origins:
The origin, or list of origins to allow requests from.
The origin(s) may be regular expressions, case-sensitive strings,
or else an asterisk
Default : '*'
:type origins: list, string or regex
:param methods:
The method or list of methods which the allowed origins are allowed to
access for non-simple requests.
Default : [GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE]
:type methods: list or string
:param expose_headers:
The header or list which are safe to expose to the API of a CORS API
specification.
Default : None
:type expose_headers: list or string
:param allow_headers:
The header or list of header field names which can be used when this
resource is accessed by allowed origins. The header(s) may be regular
expressions, case-sensitive strings, or else an asterisk.
Default : '*', allow all headers
:type allow_headers: list, string or regex
:param supports_credentials:
Allows users to make authenticated requests. If true, injects the
`Access-Control-Allow-Credentials` header in responses. This allows
cookies and credentials to be submitted across domains.
:note: This option cannot be used in conjuction with a '*' origin
Default : False
:type supports_credentials: bool
:param max_age:
The maximum time for which this CORS request maybe cached. This value
is set as the `Access-Control-Max-Age` header.
Default : None
:type max_age: timedelta, integer, string or None
:param send_wildcard: If True, and the origins parameter is `*`, a wildcard
`Access-Control-Allow-Origin` header is sent, rather than the
request's `Origin` header.
Default : False
:type send_wildcard: bool
:param vary_header:
If True, the header Vary: Origin will be returned as per the W3
implementation guidelines.
Setting this header when the `Access-Control-Allow-Origin` is
dynamically generated (e.g. when there is more than one allowed
origin, and an Origin than '*' is returned) informs CDNs and other
caches that the CORS headers are dynamic, and cannot be cached.
If False, the Vary header will never be injected or altered.
Default : True
:type vary_header: bool
:param automatic_options:
Only applies to the `cross_origin` decorator. If True, Flask-CORS will
override Flask's default OPTIONS handling to return CORS headers for
OPTIONS requests.
Default : True
:type automatic_options: bool
"""
_options = kwargs
def decorator(f):
LOG.debug("Enabling %s for cross_origin using options:%s", f, _options)
# If True, intercept OPTIONS requests by modifying the view function,
# replicating Flask's default behavior, and wrapping the response with
# CORS headers.
#
# If f.provide_automatic_options is unset or True, Flask's route
# decorator (which is actually wraps the function object we return)
# intercepts OPTIONS handling, and requests will not have CORS headers
if _options.get('automatic_options', True):
f.required_methods = getattr(f, 'required_methods', set())
f.required_methods.add('OPTIONS')
f.provide_automatic_options = False
def wrapped_function(*args, **kwargs):
# Handle setting of Flask-Cors parameters
options = get_cors_options(current_app, _options)
if options.get('automatic_options') and request.method == 'OPTIONS':
resp = current_app.make_default_options_response()
else:
resp = make_response(f(*args, **kwargs))
set_cors_headers(resp, options)
setattr(resp, FLASK_CORS_EVALUATED, True)
return resp
return update_wrapper(wrapped_function, f)
return decorator

View File

@@ -0,0 +1,186 @@
# -*- coding: utf-8 -*-
"""
extension
~~~~
Flask-CORS is a simple extension to Flask allowing you to support cross
origin resource sharing (CORS) using a simple decorator.
:copyright: (c) 2016 by Cory Dolphin.
:license: MIT, see LICENSE for more details.
"""
from flask import request
from .core import *
LOG = logging.getLogger(__name__)
class CORS(object):
"""
Initializes Cross Origin Resource sharing for the application. The
arguments are identical to :py:func:`cross_origin`, with the addition of a
`resources` parameter. The resources parameter defines a series of regular
expressions for resource paths to match and optionally, the associated
options to be applied to the particular resource. These options are
identical to the arguments to :py:func:`cross_origin`.
The settings for CORS are determined in the following order
1. Resource level settings (e.g when passed as a dictionary)
2. Keyword argument settings
3. App level configuration settings (e.g. CORS_*)
4. Default settings
Note: as it is possible for multiple regular expressions to match a
resource path, the regular expressions are first sorted by length,
from longest to shortest, in order to attempt to match the most
specific regular expression. This allows the definition of a
number of specific resource options, with a wildcard fallback
for all other resources.
:param resources:
The series of regular expression and (optionally) associated CORS
options to be applied to the given resource path.
If the argument is a dictionary, it's keys must be regular expressions,
and the values must be a dictionary of kwargs, identical to the kwargs
of this function.
If the argument is a list, it is expected to be a list of regular
expressions, for which the app-wide configured options are applied.
If the argument is a string, it is expected to be a regular expression
for which the app-wide configured options are applied.
Default : Match all and apply app-level configuration
:type resources: dict, iterable or string
:param origins:
The origin, or list of origins to allow requests from.
The origin(s) may be regular expressions, case-sensitive strings,
or else an asterisk
Default : '*'
:type origins: list, string or regex
:param methods:
The method or list of methods which the allowed origins are allowed to
access for non-simple requests.
Default : [GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE]
:type methods: list or string
:param expose_headers:
The header or list which are safe to expose to the API of a CORS API
specification.
Default : None
:type expose_headers: list or string
:param allow_headers:
The header or list of header field names which can be used when this
resource is accessed by allowed origins. The header(s) may be regular
expressions, case-sensitive strings, or else an asterisk.
Default : '*', allow all headers
:type allow_headers: list, string or regex
:param supports_credentials:
Allows users to make authenticated requests. If true, injects the
`Access-Control-Allow-Credentials` header in responses. This allows
cookies and credentials to be submitted across domains.
:note: This option cannot be used in conjuction with a '*' origin
Default : False
:type supports_credentials: bool
:param max_age:
The maximum time for which this CORS request maybe cached. This value
is set as the `Access-Control-Max-Age` header.
Default : None
:type max_age: timedelta, integer, string or None
:param send_wildcard: If True, and the origins parameter is `*`, a wildcard
`Access-Control-Allow-Origin` header is sent, rather than the
request's `Origin` header.
Default : False
:type send_wildcard: bool
:param vary_header:
If True, the header Vary: Origin will be returned as per the W3
implementation guidelines.
Setting this header when the `Access-Control-Allow-Origin` is
dynamically generated (e.g. when there is more than one allowed
origin, and an Origin than '*' is returned) informs CDNs and other
caches that the CORS headers are dynamic, and cannot be cached.
If False, the Vary header will never be injected or altered.
Default : True
:type vary_header: bool
"""
def __init__(self, app=None, **kwargs):
self._options = kwargs
if app is not None:
self.init_app(app, **kwargs)
def init_app(self, app, **kwargs):
# The resources and options may be specified in the App Config, the CORS constructor
# or the kwargs to the call to init_app.
options = get_cors_options(app, self._options, kwargs)
# Flatten our resources into a list of the form
# (pattern_or_regexp, dictionary_of_options)
resources = parse_resources(options.get('resources'))
# Compute the options for each resource by combining the options from
# the app's configuration, the constructor, the kwargs to init_app, and
# finally the options specified in the resources dictionary.
resources = [
(pattern, get_cors_options(app, options, opts))
for (pattern, opts) in resources
]
# Create a human readable form of these resources by converting the compiled
# regular expressions into strings.
resources_human = {get_regexp_pattern(pattern): opts for (pattern,opts) in resources}
LOG.debug("Configuring CORS with resources: %s", resources_human)
cors_after_request = make_after_request_function(resources)
app.after_request(cors_after_request)
# Wrap exception handlers with cross_origin
# These error handlers will still respect the behavior of the route
if options.get('intercept_exceptions', True):
def _after_request_decorator(f):
def wrapped_function(*args, **kwargs):
return cors_after_request(app.make_response(f(*args, **kwargs)))
return wrapped_function
if hasattr(app, 'handle_exception'):
app.handle_exception = _after_request_decorator(
app.handle_exception)
app.handle_user_exception = _after_request_decorator(
app.handle_user_exception)
def make_after_request_function(resources):
def cors_after_request(resp):
# If CORS headers are set in a view decorator, pass
if resp.headers is not None and resp.headers.get(ACL_ORIGIN):
LOG.debug('CORS have been already evaluated, skipping')
return resp
for res_regex, res_options in resources:
if try_match(request.path, res_regex):
LOG.debug("Request to '%s' matches CORS resource '%s'. Using options: %s",
request.path, get_regexp_pattern(res_regex), res_options)
set_cors_headers(resp, res_options)
break
else:
LOG.debug('No CORS rule matches')
return resp
return cors_after_request

View File

@@ -0,0 +1 @@
__version__ = '3.0.8'

View File

@@ -1,7 +1,9 @@
from flask import Flask
from flask import request
from amazonservices import uploader, analyzer;
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
from flask import jsonify
@app.route('/')