Skip to content

Commit ca23b7b

Browse files
authored
Merge pull request pallets#2994 from jarek/werkzeug-640-exceptions-during-bind
Handle errors during create_url_adapter
2 parents 3394191 + a5709e7 commit ca23b7b

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

CHANGES.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ Unreleased
1212
- :meth:`flask.RequestContext.copy` includes the current session
1313
object in the request context copy. This prevents ``flask.session``
1414
pointing to an out-of-date object. (`#2935`)
15+
- Using built-in RequestContext, unprintable Unicode characters in Host
16+
header will result in a HTTP 400 response and not HTTP 500 as previously.
17+
(`#2994`)
1518

1619
.. _#2935: https://github.com/pallets/flask/issues/2935
20+
.. _#2994: https://github.com/pallets/flask/pull/2994
1721

1822

1923
Version 1.0.3

flask/ctx.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,11 @@ def __init__(self, app, environ, request=None, session=None):
282282
if request is None:
283283
request = app.request_class(environ)
284284
self.request = request
285-
self.url_adapter = app.create_url_adapter(self.request)
285+
self.url_adapter = None
286+
try:
287+
self.url_adapter = app.create_url_adapter(self.request)
288+
except HTTPException as e:
289+
self.request.routing_exception = e
286290
self.flashes = None
287291
self.session = session
288292

@@ -305,7 +309,8 @@ def __init__(self, app, environ, request=None, session=None):
305309
# functions.
306310
self._after_request_functions = []
307311

308-
self.match_request()
312+
if self.url_adapter is not None:
313+
self.match_request()
309314

310315
def _get_g(self):
311316
return _app_ctx_stack.top.g

tests/test_reqctx.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,57 @@ def index():
229229
assert response.status_code == 500
230230
assert not flask.request
231231
assert not flask.current_app
232+
233+
234+
def test_bad_environ_raises_bad_request():
235+
app = flask.Flask(__name__)
236+
237+
# We cannot use app.test_client() for the Unicode-rich Host header,
238+
# because werkzeug enforces latin1 on Python 2.
239+
# However it works when actually passed to the server.
240+
241+
from flask.testing import make_test_environ_builder
242+
builder = make_test_environ_builder(app)
243+
environ = builder.get_environ()
244+
245+
# use a non-printable character in the Host - this is key to this test
246+
environ['HTTP_HOST'] = u'\x8a'
247+
248+
with app.request_context(environ):
249+
response = app.full_dispatch_request()
250+
assert response.status_code == 400
251+
252+
253+
def test_environ_for_valid_idna_completes():
254+
app = flask.Flask(__name__)
255+
256+
@app.route('/')
257+
def index():
258+
return 'Hello World!'
259+
260+
# We cannot use app.test_client() for the Unicode-rich Host header,
261+
# because werkzeug enforces latin1 on Python 2.
262+
# However it works when actually passed to the server.
263+
264+
from flask.testing import make_test_environ_builder
265+
builder = make_test_environ_builder(app)
266+
environ = builder.get_environ()
267+
268+
# these characters are all IDNA-compatible
269+
environ['HTTP_HOST'] = u'ąśźäüжŠßя.com'
270+
271+
with app.request_context(environ):
272+
response = app.full_dispatch_request()
273+
274+
assert response.status_code == 200
275+
276+
277+
def test_normal_environ_completes():
278+
app = flask.Flask(__name__)
279+
280+
@app.route('/')
281+
def index():
282+
return 'Hello World!'
283+
284+
response = app.test_client().get('/', headers={'host': 'xn--on-0ia.com'})
285+
assert response.status_code == 200

0 commit comments

Comments
 (0)