https://github.com/python/cpython/commit/7d3b991f4a064e01e1211c31cb5bf3fb62a510d1
commit: 7d3b991f4a064e01e1211c31cb5bf3fb62a510d1
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-05T11:22:09Z
summary:

[3.15] gh-54930: Send a status line in error responses to malformed request 
lines (GH-152980) (GH-153092)

Previously such error responses were sent in the bare HTTP/0.9 style,
without a status line and headers.
(cherry picked from commit 2ab620b41af57e24c11c131bec02f682561ecfaa)

Co-authored-by: Serhiy Storchaka <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst
M Lib/http/server.py
M Lib/test/test_httpservers.py

diff --git a/Lib/http/server.py b/Lib/http/server.py
index ebc85052aecb900..095b5744bd12fc6 100644
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -334,10 +334,13 @@ def parse_request(self):
                     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 @@ def parse_request(self):
                     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 @@ def parse_request(self):
         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)
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
index 574529c70741d8f..70349c6c8869a94 100644
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -386,6 +386,8 @@ def test_simple_get(self):
     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 @@ def test_http_0_9(self):
         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
index 000000000000000..1cfc0212c609a69
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-03-21-10-00.gh-issue-54930.hq09Er.rst
@@ -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.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to