diff --git a/.travis.yml b/.travis.yml index 5884719..cf26ab2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,23 +7,24 @@ python: - '3.4' - '3.5' - '3.6' + - '3.7' + - '3.8' - pypy -# from https://github.com/travis-ci/travis-ci/issues/9815 -# https://github.com/travis-ci/travis-ci/issues/9069#issuecomment-425720905 -# Enable 3.7 without globally enabling sudo and dist: xenial for other build jobs matrix: - include: - - python: 3.7 - dist: xenial - sudo: true - + exclude: + - python: 3.4 + - env: + - DEPEENDENCIES="flask==1.1" + env: -- FLASK=0.10.1 -- FLASK=0.10 +- DEPEENDENCIES="flask==0.10.1 werkzeug==0.16.1" # pin werkzeug for Flask 10, 10.1 since Flask does not pin it itself. +- DEPEENDENCIES="flask==0.10 werkzeug==0.16.1" +- DEPEENDENCIES="flask==1.0" +- DEPEENDENCIES="flask==1.1" install: - - pip install -U setuptools pep8 six coverage docutils pygments flask==$FLASK + - pip install -U setuptools pep8 six coverage docutils pygments packaging $DEPEENDENCIES script: - coverage erase diff --git a/examples/app_based_example.py b/examples/app_based_example.py index e616aa6..b5ff821 100644 --- a/examples/app_based_example.py +++ b/examples/app_based_example.py @@ -124,7 +124,7 @@ def get_exception(): Browsers will first make a preflight request to verify that the resource allows cross-origin POSTs with a JSON Content-Type, which can be simulated as: - $ curl --include -X OPTIONS http://127.0.0.1:5000/exception \ + $ curl --include -X OPTIONS http://127.0.0.1:5000/api/exception \ --header Access-Control-Request-Method:POST \ --header Access-Control-Request-Headers:Content-Type \ --header Origin:www.examplesite.com diff --git a/flask_cors/extension.py b/flask_cors/extension.py index 6a585aa..466869e 100644 --- a/flask_cors/extension.py +++ b/flask_cors/extension.py @@ -10,6 +10,10 @@ """ from flask import request from .core import * +try: + from urllib.parse import unquote_plus +except ImportError: + from urllib import unquote_plus LOG = logging.getLogger(__name__) @@ -173,9 +177,9 @@ def cors_after_request(resp): if resp.headers is not None and resp.headers.get(ACL_ORIGIN): LOG.debug('CORS have been already evaluated, skipping') return resp - + normalized_path = unquote_plus(request.path) for res_regex, res_options in resources: - if try_match(request.path, res_regex): + if try_match(normalized_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) diff --git a/setup.py b/setup.py index 32e7999..d117d96 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,8 @@ platforms='any', install_requires=install_requires, tests_require=[ - 'nose' + 'nose', + 'packaging' ], test_suite='nose.collector', classifiers=[ diff --git a/tests/decorator/test_exception_interception.py b/tests/decorator/test_exception_interception.py index 87fc04f..fe42d3d 100644 --- a/tests/decorator/test_exception_interception.py +++ b/tests/decorator/test_exception_interception.py @@ -8,6 +8,10 @@ :copyright: (c) 2016 by Cory Dolphin. :license: MIT, see LICENSE for more details. """ +import unittest + +import flask +from packaging import version from ..base_test import FlaskCorsTestCase from flask import Flask, abort from flask_cors import * @@ -198,6 +202,9 @@ def get_with_origins(path): self.assertEqual(resp.status_code, 200) self.assertFalse(ACL_ORIGIN in resp.headers) + @unittest.skipIf(version.parse(flask.__version__) >= version.parse("1.1"), + "Flask 1.1 changed interception behavior, so after request handlers are always run. " + "This obviates the need for our hacky interception") def test_acl_uncaught_exception_500(self): ''' Uncaught exceptions will trigger Flask's internal exception diff --git a/tests/extension/test_app_extension.py b/tests/extension/test_app_extension.py index 6ebca5f..597b744 100644 --- a/tests/extension/test_app_extension.py +++ b/tests/extension/test_app_extension.py @@ -204,7 +204,7 @@ class AppExtensionString(FlaskCorsTestCase): def setUp(self): self.app = Flask(__name__) CORS(self.app, resources=r'/api/*', - headers='Content-Type', + allow_headers='Content-Type', expose_headers='X-Total-Count', origins='http://bar.com') @@ -225,6 +225,10 @@ def overridden(): def index(): return 'Welcome' + @self.app.route('/foo.txt') + def foo_txt(): + return 'Welcome' + def test_exposed(self): for path in '/api/v1/foo', '/api/v1/bar': for resp in self.iter_responses(path, origin='http://bar.com'):