Skip to content

Commit

Permalink
Fixed an issue where the default OPTIONS response was
Browse files Browse the repository at this point in the history
not exposing all valid methods in the `Allow` header.

This fixes pallets#97

Signed-off-by: Armin Ronacher <armin.ronacher@active-4.com>
  • Loading branch information
mitsuhiko committed Jul 27, 2010
1 parent 8a14a87 commit dbf55de
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Expand Up @@ -13,6 +13,9 @@ Version 0.6.1


Bugfix release, release date to be announced. Bugfix release, release date to be announced.


- Fixed an issue where the default `OPTIONS` response was
not exposing all valid methods in the `Allow` header.

Version 0.6 Version 0.6
----------- -----------


Expand Down
23 changes: 19 additions & 4 deletions flask/app.py
Expand Up @@ -19,7 +19,8 @@


from werkzeug import ImmutableDict from werkzeug import ImmutableDict
from werkzeug.routing import Map, Rule from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, InternalServerError from werkzeug.exceptions import HTTPException, InternalServerError, \
MethodNotAllowed


from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \ from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \
_tojson_filter, _endpoint_from_view_func _tojson_filter, _endpoint_from_view_func
Expand Down Expand Up @@ -689,14 +690,28 @@ def dispatch_request(self):
# if we provide automatic options for this URL and the # if we provide automatic options for this URL and the
# request came with the OPTIONS method, reply automatically # request came with the OPTIONS method, reply automatically
if rule.provide_automatic_options and req.method == 'OPTIONS': if rule.provide_automatic_options and req.method == 'OPTIONS':
rv = self.response_class() return self._make_default_options_response()
rv.allow.update(rule.methods)
return rv
# otherwise dispatch to the handler for that endpoint # otherwise dispatch to the handler for that endpoint
return self.view_functions[rule.endpoint](**req.view_args) return self.view_functions[rule.endpoint](**req.view_args)
except HTTPException, e: except HTTPException, e:
return self.handle_http_exception(e) return self.handle_http_exception(e)


def _make_default_options_response(self):
# This would be nicer in Werkzeug 0.7, which however currently
# is not released. Werkzeug 0.7 provides a method called
# allowed_methods() that returns all methods that are valid for
# a given path.
methods = []
try:
_request_ctx_stack.top.url_adapter.match(method='--')
except MethodNotAllowed, e:
methods = e.valid_methods
except HTTPException, e:
pass
rv = self.response_class()
rv.allow.update(methods)
return rv

def make_response(self, rv): def make_response(self, rv):
"""Converts the return value from a view function to a real """Converts the return value from a view function to a real
response object that is an instance of :attr:`response_class`. response object that is an instance of :attr:`response_class`.
Expand Down
11 changes: 11 additions & 0 deletions tests/flask_tests.py
Expand Up @@ -120,6 +120,17 @@ def index():
assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST'] assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
assert rv.data == '' assert rv.data == ''


def test_options_on_multiple_rules(self):
app = flask.Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
return 'Hello World'
@app.route('/', methods=['PUT'])
def index_put():
return 'Aha!'
rv = app.test_client().open('/', method='OPTIONS')
assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']

def test_request_dispatching(self): def test_request_dispatching(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.route('/') @app.route('/')
Expand Down

0 comments on commit dbf55de

Please sign in to comment.