Skip to content

Commit 0262943

Browse files
serhiy-storchakaclaude
authored andcommitted
gh-54930: Send a status line in error responses to malformed request lines (GH-152980)
Previously such error responses were sent in the bare HTTP/0.9 style, without a status line and headers. (cherry picked from commit 2ab620b) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent a7e8d28 commit 0262943

3 files changed

Lines changed: 25 additions & 1 deletion

File tree

Lib/http/server.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,20 +311,23 @@ def parse_request(self):
311311
raise ValueError("unreasonable length http version")
312312
version_number = int(version_number[0]), int(version_number[1])
313313
except (ValueError, IndexError):
314+
# Send the error response with a status line and headers.
315+
self.request_version = ''
314316
self.send_error(
315317
HTTPStatus.BAD_REQUEST,
316318
"Bad request version (%r)" % version)
317319
return False
320+
self.request_version = version
318321
if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
319322
self.close_connection = False
320323
if version_number >= (2, 0):
321324
self.send_error(
322325
HTTPStatus.HTTP_VERSION_NOT_SUPPORTED,
323326
"Invalid HTTP version (%s)" % base_version_number)
324327
return False
325-
self.request_version = version
326328

327329
if not 2 <= len(words) <= 3:
330+
self.request_version = ''
328331
self.send_error(
329332
HTTPStatus.BAD_REQUEST,
330333
"Bad request syntax (%r)" % requestline)
@@ -333,6 +336,7 @@ def parse_request(self):
333336
if len(words) == 2:
334337
self.close_connection = True
335338
if command != 'GET':
339+
self.request_version = ''
336340
self.send_error(
337341
HTTPStatus.BAD_REQUEST,
338342
"Bad HTTP/0.9 request type (%r)" % command)

Lib/test/test_httpservers.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ def test_simple_get(self):
339339
def test_invalid_request(self):
340340
self.sock.send(b'POST /index.html\r\n')
341341
res = self.sock.recv(1024)
342+
# The error response is not sent in the bare HTTP/0.9 style.
343+
self.assertStartsWith(res, b'HTTP/1.0 400 ')
342344
self.assertIn(b"Bad HTTP/0.9 request type ('POST')", res)
343345

344346
def test_single_request(self):
@@ -1234,6 +1236,19 @@ def test_http_0_9(self):
12341236
self.assertEqual(result[0], b'<html><body>Data</body></html>\r\n')
12351237
self.verify_get_called()
12361238

1239+
@support.subTests('request,code', [
1240+
(b'GET / FUBAR\r\n\r\n', 400), # bad version
1241+
(b'GET / HTTP/2.0\r\n\r\n', 505), # unsupported version
1242+
(b'GET\r\n', 400), # bad syntax
1243+
(b'POST /\r\n', 400), # bad HTTP/0.9 request type
1244+
])
1245+
def test_request_line_error_has_status_line(self, request, code):
1246+
self.handler = SocketlessRequestHandler()
1247+
result = self.send_typical_request(request)
1248+
self.assertStartsWith(result[0], b'HTTP/1.1 %d ' % code)
1249+
self.verify_expected_headers(result[1:result.index(b'\r\n')])
1250+
self.assertFalse(self.handler.get_called)
1251+
12371252
def test_extra_space(self):
12381253
result = self.send_typical_request(
12391254
b'GET /spaced out HTTP/1.1\r\n'
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Error responses of :class:`http.server.BaseHTTPRequestHandler` to malformed
2+
request lines now include a status line and headers instead of being sent in
3+
the bare HTTP/0.9 style.
4+
Only a valid HTTP/0.9 request (a two-word ``GET`` request line) now receives
5+
an HTTP/0.9 style response.

0 commit comments

Comments
 (0)