]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-54930: Send a status line in error responses to malformed request lines (GH-152980)
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 5 Jul 2026 10:48:23 +0000 (13:48 +0300)
committerGitHub <noreply@github.com>
Sun, 5 Jul 2026 10:48:23 +0000 (13:48 +0300)
Previously such error responses were sent in the bare HTTP/0.9 style,
without a status line and headers.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Lib/http/server.py
Lib/test/test_httpservers.py
Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst [new file with mode: 0644]

index ebc85052aecb9006e4e597a6d5d9b77d5a742463..095b5744bd12fc675892b2231ac8032ec5c18045 100644 (file)
@@ -334,10 +334,13 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
                     raise ValueError("unreasonable length http version")
                 version_number = int(version_number[0]), int(version_number[1])
             except (ValueError, IndexError):
+                # Send the error response with a status line and headers.
+                self.request_version = ''
                 self.send_error(
                     HTTPStatus.BAD_REQUEST,
                     "Bad request version (%r)" % version)
                 return False
+            self.request_version = version
             if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
                 self.close_connection = False
             if version_number >= (2, 0):
@@ -345,9 +348,9 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
                     HTTPStatus.HTTP_VERSION_NOT_SUPPORTED,
                     "Invalid HTTP version (%s)" % base_version_number)
                 return False
-            self.request_version = version
 
         if not 2 <= len(words) <= 3:
+            self.request_version = ''
             self.send_error(
                 HTTPStatus.BAD_REQUEST,
                 "Bad request syntax (%r)" % requestline)
@@ -356,6 +359,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
         if len(words) == 2:
             self.close_connection = True
             if command != 'GET':
+                self.request_version = ''
                 self.send_error(
                     HTTPStatus.BAD_REQUEST,
                     "Bad HTTP/0.9 request type (%r)" % command)
index d4ae032610a91e23c42975840b8e8edb58aa2f6b..63f65a9c5cf47a97dd83ea3c5b6f8821b0696cca 100644 (file)
@@ -386,6 +386,8 @@ class HTTP09ServerTestCase(BaseTestCase):
     def test_invalid_request(self):
         self.sock.send(b'POST /index.html\r\n')
         res = self.sock.recv(1024)
+        # The error response is not sent in the bare HTTP/0.9 style.
+        self.assertStartsWith(res, b'HTTP/1.0 400 ')
         self.assertIn(b"Bad HTTP/0.9 request type ('POST')", res)
 
     def test_single_request(self):
@@ -1102,6 +1104,19 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
         self.assertEqual(result[0], b'<html><body>Data</body></html>\r\n')
         self.verify_get_called()
 
+    @support.subTests('request,code', [
+        (b'GET / FUBAR\r\n\r\n', 400),     # bad version
+        (b'GET / HTTP/2.0\r\n\r\n', 505),  # unsupported version
+        (b'GET\r\n', 400),                 # bad syntax
+        (b'POST /\r\n', 400),              # bad HTTP/0.9 request type
+    ])
+    def test_request_line_error_has_status_line(self, request, code):
+        self.handler = SocketlessRequestHandler()
+        result = self.send_typical_request(request)
+        self.assertStartsWith(result[0], b'HTTP/1.1 %d ' % code)
+        self.verify_expected_headers(result[1:result.index(b'\r\n')])
+        self.assertFalse(self.handler.get_called)
+
     def test_extra_space(self):
         result = self.send_typical_request(
             b'GET /spaced out HTTP/1.1\r\n'
diff --git a/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst b/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst
new file mode 100644 (file)
index 0000000..1cfc021
--- /dev/null
@@ -0,0 +1,5 @@
+Error responses of :class:`http.server.BaseHTTPRequestHandler` to malformed
+request lines now include a status line and headers instead of being sent in
+the bare HTTP/0.9 style.
+Only a valid HTTP/0.9 request (a two-word ``GET`` request line) now receives
+an HTTP/0.9 style response.