Skip to content

Commit 07decd5

Browse files
committed
fix(method): disallow invalid HTTP method chars
1 parent fc82581 commit 07decd5

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

httoop/messages/method.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def idempotent(self) -> bool:
3131

3232
safe_methods = ('GET', 'HEAD', 'SEARCH')
3333
idempotent_methods = ('GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE', 'SEARCH')
34-
METHOD_RE = re.compile(rb'^[A-Z0-9$-_.]{1,20}\Z', re.IGNORECASE)
34+
METHOD_RE = re.compile(rb'^[A-Z0-9$_.-]{1,20}\Z', re.IGNORECASE)
3535

3636
def __init__(self, method: str | None = None) -> None:
3737
self.set(method or 'GET')

tests/messaging/test_request_method.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import string
2+
13
import pytest
24

35
from httoop.exceptions import InvalidLine
46

7+
VALID_METHOD_CHARS = string.ascii_letters + string.digits + '$-_.'
8+
59

610
def test_method_format(request_):
711
assert f'{request_.method}' == 'GET'
@@ -10,11 +14,18 @@ def test_method_format(request_):
1014
def test_method_maxlength(request_):
1115
with pytest.raises(InvalidLine):
1216
request_.method.parse(b'A' * 21)
17+
request_.method.parse(b'A' * 20)
18+
19+
20+
@pytest.mark.parametrize('char', list(VALID_METHOD_CHARS))
21+
def test_method_valid_characters(request_, char):
22+
request_.parse(b'G%bET / HTTP/1.1' % char.encode('ASCII'))
1323

1424

15-
def test_method_valid_characters(request_):
25+
@pytest.mark.parametrize('char', set(''.join(map(chr, range(256)))) - set(VALID_METHOD_CHARS))
26+
def test_method_invalid_characters(request_, char):
1627
with pytest.raises(InvalidLine):
17-
request_.parse(b'G\x01ET / HTTP/1.1')
28+
request_.parse(b'G%bET / HTTP/1.1' % char.encode('ISO8859-1'))
1829

1930

2031
def test_request_on_safe_method_containing_request_body():

0 commit comments

Comments
 (0)