diff --git a/cheroot/server.py b/cheroot/server.py index 284cf17c72..856d07424a 100644 --- a/cheroot/server.py +++ b/cheroot/server.py @@ -162,6 +162,7 @@ FORWARD_SLASH = b'/' QUOTED_SLASH = b'%2F' QUOTED_SLASH_REGEX = re.compile(b''.join((b'(?i)', QUOTED_SLASH))) +HTTP_TOKEN_RE = re.compile(rb"^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$") _STOPPING_FOR_INTERRUPT = Exception() # sentinel used during shutdown @@ -826,6 +827,10 @@ def read_request_line(self): # noqa: C901 # FIXME self.simple_response('400 Bad Request', 'Malformed Request-Line') return False + if not HTTP_TOKEN_RE.match(method): + self.simple_response('400 Bad Request', 'Malformed method name') + return False + self.uri = uri self.method = method.upper() diff --git a/cheroot/test/test_core.py b/cheroot/test/test_core.py index cd3841d428..aa7ffe2c3a 100644 --- a/cheroot/test/test_core.py +++ b/cheroot/test/test_core.py @@ -420,6 +420,17 @@ def test_garbage_in(test_client): raise +def test_invalid_character_in_http_method(test_client): + """Check that methods with invalid token characters are rejected.""" + c = test_client.get_connection() + c._output(b'GE(T / HTTP/1.1\r\nHost: localhost\r\n\r\n') + c._send_output() + response = _get_http_response(c, method='GET') + response.begin() + assert response.status == HTTP_BAD_REQUEST + c.close() + + class CloseController: """Controller for testing the close callback."""