diff --git a/CHANGES b/CHANGES index c22a6626..f9f3c82d 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,8 @@ Relase date to be decided, codename to be chosen. the implementation of the sessions can be changed without having to override the Flask class. - Empty session cookies are now deleted properly automatically. +- View functions can now opt out of getting the automatic + OPTIONS implementation. Version 0.7.2 ------------- diff --git a/flask/app.py b/flask/app.py index 67e8298a..db9d2af0 100644 --- a/flask/app.py +++ b/flask/app.py @@ -703,15 +703,24 @@ class Flask(_PackageBoundObject): endpoint = _endpoint_from_view_func(view_func) options['endpoint'] = endpoint methods = options.pop('methods', None) + # if the methods are not given and the view_func object knows its # methods we can use that instead. If neither exists, we go with # a tuple of only `GET` as default. if methods is None: methods = getattr(view_func, 'methods', None) or ('GET',) - provide_automatic_options = False - if 'OPTIONS' not in methods: - methods = tuple(methods) + ('OPTIONS',) - provide_automatic_options = True + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + provide_automatic_options = getattr(view_func, + 'provide_automatic_options', None) + + if provide_automatic_options is None: + if 'OPTIONS' not in methods: + methods = tuple(methods) + ('OPTIONS',) + provide_automatic_options = True + else: + provide_automatic_options = False # due to a werkzeug bug we need to make sure that the defaults are # None if they are an empty dictionary. This should not be necessary diff --git a/tests/flask_tests.py b/tests/flask_tests.py index e13dfd36..095f4bad 100644 --- a/tests/flask_tests.py +++ b/tests/flask_tests.py @@ -194,6 +194,23 @@ class BasicFunctionalityTestCase(unittest.TestCase): rv = app.test_client().open('/', method='OPTIONS') assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] + def test_options_handling_disabled(self): + app = flask.Flask(__name__) + def index(): + return 'Hello World!' + index.provide_automatic_options = False + app.route('/')(index) + rv = app.test_client().open('/', method='OPTIONS') + assert rv.status_code == 405 + + app = flask.Flask(__name__) + def index2(): + return 'Hello World!' + index2.provide_automatic_options = True + app.route('/', methods=['OPTIONS'])(index2) + rv = app.test_client().open('/', method='OPTIONS') + assert sorted(rv.allow) == ['OPTIONS'] + def test_request_dispatching(self): app = flask.Flask(__name__) @app.route('/')