From e3ad2a3a2d45d796bada36ae9f9b4f87c4f15b6a Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 15 Aug 2017 22:51:24 -0600 Subject: No longer allow lowercase HTTP methods --- waitress/parser.py | 16 ++++++++++++++-- waitress/tests/test_parser.py | 10 +++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/waitress/parser.py b/waitress/parser.py index fc71d68..fcc16d8 100644 --- a/waitress/parser.py +++ b/waitress/parser.py @@ -291,8 +291,20 @@ def crack_first_line(line): version = m.group(5) else: version = None - command = m.group(1).upper() + method = m.group(1) + + # the request methods that are currently defined are all uppercase: + # https://www.iana.org/assignments/http-methods/http-methods.xhtml and + # the request method is case sensitive according to + # https://tools.ietf.org/html/rfc7231#section-4.1 + + # By disallowing anything but uppercase methods we save poor + # unsuspecting souls from sending lowercase HTTP methods to waitress + # and having the request complete, while servers like nginx drop the + # request onto the floor. + if method != method.upper(): + raise ParsingError('Malformed HTTP method "%s"' % tostr(method)) uri = m.group(2) - return command, uri, version + return method, uri, version else: return b'', b'', b'' diff --git a/waitress/tests/test_parser.py b/waitress/tests/test_parser.py index 781d7c7..9b1a7e8 100644 --- a/waitress/tests/test_parser.py +++ b/waitress/tests/test_parser.py @@ -288,15 +288,19 @@ class Test_crack_first_line(unittest.TestCase): return crack_first_line(line) def test_crack_first_line_matchok(self): - result = self._callFUT(b'get / HTTP/1.0') + result = self._callFUT(b'GET / HTTP/1.0') self.assertEqual(result, (b'GET', b'/', b'1.0')) + def test_crack_first_line_lowercase_method(self): + from waitress.parser import ParsingError + self.assertRaises(ParsingError, self._callFUT, b'get / HTTP/1.0') + def test_crack_first_line_nomatch(self): - result = self._callFUT(b'get / bleh') + result = self._callFUT(b'GET / bleh') self.assertEqual(result, (b'', b'', b'')) def test_crack_first_line_missing_version(self): - result = self._callFUT(b'get /') + result = self._callFUT(b'GET /') self.assertEqual(result, (b'GET', b'/', None)) class TestHTTPRequestParserIntegration(unittest.TestCase): -- cgit v1.2.1