Skip to content

Commit

Permalink
fix #1187: Allow non-ASCII characters in status_line
Browse files Browse the repository at this point in the history
Uncommon, but valid.
  • Loading branch information
defnull committed Dec 18, 2019
1 parent d9903c7 commit 5c52eb0
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 1 deletion.
17 changes: 16 additions & 1 deletion bottle.py
Expand Up @@ -730,6 +730,13 @@ def mountpoint_wrapper():
def start_response(status, headerlist, exc_info=None):
if exc_info:
_raise(*exc_info)
if py3k:
# Errors here mean that the mounted WSGI app did not
# follow PEP-3333 (which requires latin1) or used a
# pre-encoding other than utf8 :/
status = status.encode('latin1').decode('utf8')
headerlist = [k, v.encode('latin1').decode('utf8')
for k, v in headerlist]
rs.status = status
for name, value in headerlist:
rs.add_header(name, value)
Expand Down Expand Up @@ -1108,7 +1115,7 @@ def wsgi(self, environ, start_response):
or environ['REQUEST_METHOD'] == 'HEAD':
if hasattr(out, 'close'): out.close()
out = []
start_response(response._status_line, response.headerlist)
start_response(response._wsgi_status_line(), response.headerlist)
return out
except (KeyboardInterrupt, SystemExit, MemoryError):
raise
Expand Down Expand Up @@ -1708,6 +1715,8 @@ def _set_status(self, status):
if isinstance(status, int):
code, status = status, _HTTP_STATUS_LINES.get(status)
elif ' ' in status:
if '\n' in status or '\r' in status or '\0' in status:
raise ValueError('Status line must not include control chars.')
status = status.strip()
code = int(status.split()[0])
else:
Expand Down Expand Up @@ -1768,6 +1777,12 @@ def iter_headers(self):
allowed with the current response status code. """
return self.headerlist

def _wsgi_status_line(self):
""" WSGI conform status line (latin1-encodeable) """
if py3k:
return self._status_line.encode('utf8').decode('latin1')
return self._status_line

@property
def headerlist(self):
""" WSGI conform list of (header, value) tuples. """
Expand Down
9 changes: 9 additions & 0 deletions test/test_environ.py
Expand Up @@ -556,6 +556,15 @@ def test(): rs.status = 5
self.assertEqual(rs.status_code, 404)
self.assertEqual(rs.status_line, '404 Brain not Found')

# Unicode in status line (thanks RFC7230 :/)
if bottle.py3k:
def test(): rs.status = '400 Non-ASCÜ'
self.assertRaises(ValueError, test)
self.assertEqual(rs.status, rs.status_line)
self.assertEqual(rs.status_code, 400)
wire = rs._wsgi_status_line().encode('latin1')
self.assertEqual(rs.status, wire.decode('utf8'))

def test(): rs.status = '5 Illegal Code'
self.assertRaises(ValueError, test)
self.assertEqual(rs.status, rs.status_line) # last value
Expand Down

0 comments on commit 5c52eb0

Please sign in to comment.