]> granicus.if.org Git - python/commitdiff
Issue #28548: Parse HTTP request version even if too many words received
authorMartin Panter <vadmium+py@gmail.com>
Sat, 19 Nov 2016 01:06:37 +0000 (01:06 +0000)
committerMartin Panter <vadmium+py@gmail.com>
Sat, 19 Nov 2016 01:06:37 +0000 (01:06 +0000)
Lib/http/server.py
Lib/test/test_httpservers.py
Misc/NEWS

index e12e45bfc3809577ec861d04e870c38cad320972..61ddecc7efe4e34cb030c3534ccb7d25b8479a93 100644 (file)
@@ -267,8 +267,8 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
         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 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
         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 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
                     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:
index 4e931446b9ef845b31c281d1c8d2993a58e40988..5049538e66418170da4d7d3a07d2d08fc5a2af1b 100644 (file)
@@ -822,6 +822,16 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
         self.assertEqual(result[0], b'<html><body>Data</body></html>\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])
index 4e78b08602c206f626c088d2154812c054300c8c..9531f2e825757b7ead35b3f5097f0854010bb1b6 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -128,6 +128,9 @@ Core and Builtins
 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 #19717: Makes Path.resolve() succeed on paths that do not exist.
   Patch by Vajrasky Kok