Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Unreleased
Bugfix
~~~~~~

- A non-ASCII ``url_prefix`` configuration value is now converted to the same
"UTF-8 bytes decoded as latin-1" representation WSGI's PATH_INFO/SCRIPT_NAME
use for the actual request path, so it can now correctly match incoming
requests. Previously, a non-ASCII url_prefix could never match any request
path at all. See
https://github.com/Pylons/waitress/issues/492

- Renamed the HTTP header "Trailers" to "Trailer" to fix a typo and comply with
the correct header name as specified in RFC 7230.

Expand Down
11 changes: 11 additions & 0 deletions src/waitress/adjustments.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ def slash_fixed_str(s):
# always have a leading slash, replace any number of leading slashes
# with a single slash, and strip any trailing slashes
s = "/" + s.lstrip("/").rstrip("/")
# Per PEP 3333, WSGI's PATH_INFO/SCRIPT_NAME are represented as
# "native strings" holding raw request bytes decoded as latin-1
# (i.e. each byte becomes the code point of the same value),
# regardless of the request's actual encoding. The configured
# url_prefix, in contrast, is an ordinary Unicode string as the
# user wrote it. Encoding it the same way here (UTF-8 bytes,
# then decoded as latin-1) ensures comparisons against the
# request path (see HTTPTask.execute()) use the same
# convention on both sides, so a non-ASCII url_prefix can
# actually match. See GH #492.
s = s.encode("utf-8").decode("latin-1")
return s


Expand Down
23 changes: 23 additions & 0 deletions tests/test_adjustments.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,29 @@ def test_goodvars(self):
# localhost...
self.assertTupleEqual(("127.0.0.1", 8080), bind_pairs[0])

def test_url_prefix_non_ascii_matches_wsgi_encoded_path(self):
"""
Regression test for
https://github.com/Pylons/waitress/issues/492

A non-ASCII url_prefix must be converted to the same
"utf8-as-latin1" representation WSGI's PATH_INFO/SCRIPT_NAME
use for the actual request path (see HTTPTask.execute() in
task.py), or a non-ASCII url_prefix can never match an
incoming request's path.
"""
inst = self._makeOne(url_prefix="/日本語")

# What the request path would actually look like once the raw
# UTF-8 bytes sent by a client are decoded as latin-1, per
# PEP 3333's WSGI string convention.
expected = "/日本語".encode("utf-8").decode("latin-1")
self.assertEqual(inst.url_prefix, expected)

def test_url_prefix_ascii_is_unaffected(self):
inst = self._makeOne(url_prefix="///api/v1///")
self.assertEqual(inst.url_prefix, "/api/v1")

def test_goodvar_listen(self):
inst = self._makeOne(listen="127.0.0.1")

Expand Down