# HG changeset patch # Parent 60b6e820abe5d196508e2c0ddcfdae72805b4afa Issue #28548: Parse HTTP request version even if too many words received diff -r 60b6e820abe5 Lib/http/server.py --- a/Lib/http/server.py Fri Oct 28 19:01:46 2016 -0400 +++ b/Lib/http/server.py Tue Nov 01 01:39:42 2016 +0000 @@ -267,8 +267,8 @@ are in self.command, self.path, self.request_version and self.headers. - Return True for success, False for failure; on failure, an - error is sent back. + Return True for success, False for failure; on failure, any relevant + error response has already been sent back. """ self.command = None # set in case of error on the first line @@ -278,10 +278,13 @@ requestline = requestline.rstrip('\r\n') self.requestline = requestline words = requestline.split() - if len(words) == 3: - command, path, version = words + if len(words) == 0: + return False + + if len(words) >= 3: # Enough to determine protocol version + version = words[-1] try: - if version[:5] != 'HTTP/': + if not version.startswith('HTTP/'): raise ValueError base_version_number = version.split('/', 1)[1] version_number = base_version_number.split(".") @@ -306,22 +309,22 @@ HTTPStatus.HTTP_VERSION_NOT_SUPPORTED, "Invalid HTTP version (%s)" % base_version_number) return False - elif len(words) == 2: - command, path = words + self.request_version = version + + if not 2 <= len(words) <= 3: + self.send_error( + HTTPStatus.BAD_REQUEST, + "Bad request syntax (%r)" % requestline) + return False + command, path = words[:2] + if len(words) == 2: self.close_connection = True if command != 'GET': self.send_error( HTTPStatus.BAD_REQUEST, "Bad HTTP/0.9 request type (%r)" % command) return False - elif not words: - return False - else: - self.send_error( - HTTPStatus.BAD_REQUEST, - "Bad request syntax (%r)" % requestline) - return False - self.command, self.path, self.request_version = command, path, version + self.command, self.path = command, path # Examine the headers and look for a Connection directive. try: diff -r 60b6e820abe5 Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py Fri Oct 28 19:01:46 2016 -0400 +++ b/Lib/test/test_httpservers.py Tue Nov 01 01:39:42 2016 +0000 @@ -822,6 +822,16 @@ self.assertEqual(result[0], b'Data\r\n') self.verify_get_called() + def test_extra_space(self): + result = self.send_typical_request( + b'GET /spaced out HTTP/1.1\r\n' + b'Host: dummy\r\n' + b'\r\n' + ) + self.assertTrue(result[0].startswith(b'HTTP/1.1 400 ')) + self.verify_expected_headers(result[1:result.index(b'\r\n')]) + self.assertFalse(self.handler.get_called) + def test_with_continue_1_0(self): result = self.send_typical_request(b'GET / HTTP/1.0\r\nExpect: 100-continue\r\n\r\n') self.verify_http_server_response(result[0]) diff -r 60b6e820abe5 Misc/NEWS --- a/Misc/NEWS Fri Oct 28 19:01:46 2016 -0400 +++ b/Misc/NEWS Tue Nov 01 01:39:42 2016 +0000 @@ -99,6 +99,9 @@ Library ------- +- Issue #28548: In the "http.server" module, parse the protocol version if + possible, to avoid using HTTP 0.9 in some error responses. + - Issue #27275: Fixed implementation of pop() and popitem() methods in subclasses of accelerated OrderedDict.