Skip to content

Commit d761d0e

Browse files
committed
routing match includes newline
1 parent 365ee7e commit d761d0e

File tree

3 files changed

+19
-1
lines changed

3 files changed

+19
-1
lines changed

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ Unreleased
8383
instead of bytes. :pr:`2337`
8484
- ``safe_join`` ensures that the path remains relative if the trusted
8585
directory is the empty string. :pr:`2349`
86+
- Percent-encoded newlines (``%0a``), which are decoded by WSGI
87+
servers, are considered when routing instead of terminating the
88+
match early. :pr:`2350`
8689

8790

8891
Version 2.0.3

src/werkzeug/routing.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,11 @@ def foo_with_slug(adapter, id):
666666
``wss://``) requests. By default, rules will only match for HTTP
667667
requests.
668668
669+
.. versionchanged:: 2.1
670+
Percent-encoded newlines (``%0a``), which are decoded by WSGI
671+
servers, are considered when routing instead of terminating the
672+
match early.
673+
669674
.. versionadded:: 1.0
670675
Added ``websocket``.
671676
@@ -892,7 +897,9 @@ def _build_regex(rule: str) -> None:
892897
else:
893898
tail = ""
894899

895-
regex = f"^{''.join(regex_parts)}{tail}$"
900+
# Use \Z instead of $ to avoid matching before a %0a decoded to
901+
# a \n by WSGI.
902+
regex = rf"^{''.join(regex_parts)}{tail}$\Z"
896903
self._regex = re.compile(regex)
897904

898905
def match(

tests/test_routing.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,3 +1346,11 @@ def test_rule_websocket_methods():
13461346
methods=["get", "head", "options", "post"],
13471347
)
13481348
r.Rule("/ws", endpoint="ws", websocket=True, methods=["get", "head", "options"])
1349+
1350+
1351+
def test_newline_match():
1352+
m = r.Map([r.Rule("/hello", endpoint="hello")])
1353+
a = m.bind("localhost")
1354+
1355+
with pytest.raises(r.NotFound):
1356+
a.match("/hello\n")

0 commit comments

Comments
 (0)