Skip to content

Commit dbf55de

Browse files
committed
Fixed an issue where the default OPTIONS response was
not exposing all valid methods in the `Allow` header. This fixes pallets#97 Signed-off-by: Armin Ronacher <[email protected]>
1 parent 8a14a87 commit dbf55de

3 files changed

Lines changed: 33 additions & 4 deletions

File tree

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Version 0.6.1
1313

1414
Bugfix release, release date to be announced.
1515

16+
- Fixed an issue where the default `OPTIONS` response was
17+
not exposing all valid methods in the `Allow` header.
18+
1619
Version 0.6
1720
-----------
1821

flask/app.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
from werkzeug import ImmutableDict
2121
from werkzeug.routing import Map, Rule
22-
from werkzeug.exceptions import HTTPException, InternalServerError
22+
from werkzeug.exceptions import HTTPException, InternalServerError, \
23+
MethodNotAllowed
2324

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

699+
def _make_default_options_response(self):
700+
# This would be nicer in Werkzeug 0.7, which however currently
701+
# is not released. Werkzeug 0.7 provides a method called
702+
# allowed_methods() that returns all methods that are valid for
703+
# a given path.
704+
methods = []
705+
try:
706+
_request_ctx_stack.top.url_adapter.match(method='--')
707+
except MethodNotAllowed, e:
708+
methods = e.valid_methods
709+
except HTTPException, e:
710+
pass
711+
rv = self.response_class()
712+
rv.allow.update(methods)
713+
return rv
714+
700715
def make_response(self, rv):
701716
"""Converts the return value from a view function to a real
702717
response object that is an instance of :attr:`response_class`.

tests/flask_tests.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ def index():
120120
assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
121121
assert rv.data == ''
122122

123+
def test_options_on_multiple_rules(self):
124+
app = flask.Flask(__name__)
125+
@app.route('/', methods=['GET', 'POST'])
126+
def index():
127+
return 'Hello World'
128+
@app.route('/', methods=['PUT'])
129+
def index_put():
130+
return 'Aha!'
131+
rv = app.test_client().open('/', method='OPTIONS')
132+
assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
133+
123134
def test_request_dispatching(self):
124135
app = flask.Flask(__name__)
125136
@app.route('/')

0 commit comments

Comments
 (0)